回答と説明をありがとうございました!
あなたは私にすべての決定的なキックを与えたので、私はそれを理解しました。意図的に完全な例を追加しました。
あなたのアドバイス (Ron BI と Dennis) に従って、まず ViewModel についてもっと読みたいと思いました。
http://msdn.microsoft.com/en-ca/magazine/dd419663.aspxの下には、非静的クラスの背後にある例があります。したがって、解決策は、ユーザー コントロールに新しいクラスを追加するだけでした (前述のサイトに示されているとおりです - 図 3 - 一部の名前が変更されました - 著作権は Josh Smith joshsmithonwpf.wordpress.com に属します):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
namespace WpfCommandControl
{
class CommandImplementation : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
public CommandImplementation(Action<object> execute)
: this(execute, null)
{
}
public CommandImplementation(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion // ICommand Members
}
}
次に、ユーザーコントロールの「ウィンドウ」で
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
namespace WpfCommandControl
{
public partial class CommandControl : UserControl, INotifyPropertyChanged
{
#region [ Private Members ]
private bool _canActivated = false;
private int _counter = 0;
CommandImplementation _activateCommand;
#endregion
#region [ Properties ]
public int CommandCounter
{
get
{
return _counter;
}
set
{
_counter = value;
OnNotifyPropertyChanged("CommandCounter");
}
}
public bool CanActivated
{
get
{
return _canActivated;
}
set
{
_canActivated = value;
OnNotifyPropertyChanged("CanActivated");
}
}
#endregion
#region [ Property_Changed_Utilities ]
public event PropertyChangedEventHandler PropertyChanged;
private void OnNotifyPropertyChanged(String info)
{
// Note: Do not forget to add interface "INotifyPropertyChanged" to your class.
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#endregion
# region [ Commands ]
public ICommand ActivateCommand
{
get
{
return _activateCommand;
}
}
#endregion
#region [ Constructor ]
public CommandControl()
{
InitializeComponent();
_activateCommand = new CommandImplementation(param => this.Activate(), param => this.CanActivated);
}
#endregion
#region [ Methods ]
void Activate()
{
CommandCounter++;
}
#endregion
}
}
最も重要な部分:
コマンドはプロパティとして実装されます:
public ICommand ActivateCommand
{
get
{
return _activateCommand;
}
}
そのため、ユーザー コントロールのコンストラクターで Lambda-Expression を使用してインスタンス化された実際のインスタンス関連のコマンドが返されるようにします。
public CommandControl()
{
InitializeComponent();
_activateCommand = new CommandImplementation(param => this.Activate(), param => this.CanActivated);
}
ラムダ - 式は、ロジックへの接続を開始します。
param => this.Activate()
コマンドが起動されると実行される Activate() 関数の場合
void Activate()
{
CommandCounter++;
}
と
param => this.CanActivated
ICommand CanExecute プロパティの背後にあるローカル ロジックを渡し、コマンドをいつ実行できるかを制御できるようにします。
私の場合、CheckBoxにバインドできるプロパティを使用しましたが、別の方法で行うこともできます...
public bool CanActivated
{
get
{
return _canActivated;
}
set
{
_canActivated = value;
OnNotifyPropertyChanged("CanActivated");
}
}
これも Josh Smith joshsmithonwpf.wordpress.com に示されているとおりです。コマンド プロパティの GET 部分で必要に応じて、プライベート メンバーが null であるかどうかを確認し、新しいインスタンスを配信するかどうかを確認する代わりに、コンストラクターでインスタンス化するように変更しました。
コードの残りの部分は、MSDN に示されているように、必要なプロパティと OnNotifyPropertyChanged の実装です。
XAML はシンプルで、概念実証用です。
<UserControl x:Class="WpfCommandControl.CommandControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfCommandControl"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="300"
d:DesignWidth="300"
mc:Ignorable="d">
<Grid>
<StackPanel>
<CheckBox Content="Activate" IsChecked="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}, Path=CanActivated}" />
<Button Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=UserControl},
Path=ActivateCommand}"
Content="Click me"
IsEnabled="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=UserControl},
Path=CanActivated}" />
<Label Content="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}, Path=CommandCounter}" IsEnabled="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}, Path=CanActivated}" />
</StackPanel>
</Grid>
ご覧のとおり、CheckBox しかありません。バインディングは、ボタンの有効化/無効化を提供します。ボタンをクリックすると、単純にカウンターをインクリメントするコマンドが起動されます。これは、再びラベルに表示され、バインディングを介して表示されます。
すべてをまとめる:
4 つのユーザー コントロールを含む 1 つの単純な XAML フォーム:
<Window x:Class="CommandsTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CommandsTest"
xmlns:uctrl="clr-namespace:WpfCommandControl;assembly=WpfCommandControl"
Title="MainWindow"
Width="525"
Height="350">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<uctrl:CommandControl Grid.Row="0" Grid.Column="0" />
<uctrl:CommandControl Grid.Row="0" Grid.Column="1" />
<uctrl:CommandControl Grid.Row="1" Grid.Column="0" />
<uctrl:CommandControl Grid.Row="1" Grid.Column="1" />
</Grid>
すべてのコントロールでコマンドを実行することは、要素内で必要に応じて行われます。
すべては WPF の方法で解決されます。つまり、GUI 要素と直接やり取りすることなくコマンドとバインドを使用するため、コード ビハインドを更新する必要なく GUI を交換できます。
WPF でカスタム コマンドを実装する別の (インスタンス セーフな) 方法もあると教えていただき、ありがとうございます。