簡単なセットアップがあります。コマンドにバインドするPopulatingイベントを含むautocompleteboxです。私が使う
clr-namespace:System.Windows.Interactivity;Assembly=System.Windows.Interactivity
(これを行うためのより良い名前空間はありますか?)
それをバインドすることは大したことではありません。大したことは、そのPopulatingEventArgs引数をバインドされたコマンドに渡すことです。
では、特にPRISMおよび一般的なMVVMのベストプラクティスに従ってそれを行うにはどうすればよいですか?
組み込みの方法はないので、次のようにします。
従来のインタラクショントリガーは次のように使用されます。
<Button Content="I am a button">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<i:InvokeCommandAction Command="{Binding CommandWithNoArgs}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
バインディングを介してEventArgs
イベントのMouseEnter
にアクセスすることはできないため、それを破棄する部分を変更する必要があります。
たまたま、その部分はInvokeCommandAction
です。
「それで、私たちはそれをサブクラス化し、ずっと私たちを待っていた便利なメソッドをオーバーライドするつもりです」は私が書きたかったものです。しかし、クラスは封印されています。
したがって、その親(抽象)クラスをサブクラス化する必要があります:TriggerAction<DependencyObject>
最も基本的な実装は次のとおりです。
public class InteractiveCommand : TriggerAction<DependencyObject>
{
protected override void Invoke(object parameter)
{
}
}
そして、そのparameter
はあなたのEventArgs
です!
しかし、それはそれほど単純ではありません。通常のInvokeCommandAction
の動作を再現する必要があります。
Reflectorを介して逆コンパイルしました(ただし、公式ソースを参照してください。私は怠け者です)。
CommandParameter
依存関係プロパティについては気にしません。InvokeCommandAction
の代わりにこれを使用する場合、実際には毎回EventArgs
が必要であると想定します。 。
これがフルクラスです(WPFのみ。SilverLightの編集を参照)。
public class InteractiveCommand : TriggerAction<DependencyObject>
{
protected override void Invoke(object parameter)
{
if (base.AssociatedObject != null)
{
ICommand command = this.ResolveCommand();
if ((command != null) && command.CanExecute(parameter))
{
command.Execute(parameter);
}
}
}
private ICommand ResolveCommand()
{
ICommand command = null;
if (this.Command != null)
{
return this.Command;
}
if (base.AssociatedObject != null)
{
foreach (PropertyInfo info in base.AssociatedObject.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (typeof(ICommand).IsAssignableFrom(info.PropertyType) && string.Equals(info.Name, this.CommandName, StringComparison.Ordinal))
{
command = (ICommand)info.GetValue(base.AssociatedObject, null);
}
}
}
return command;
}
private string commandName;
public string CommandName
{
get
{
base.ReadPreamble();
return this.commandName;
}
set
{
if (this.CommandName != value)
{
base.WritePreamble();
this.commandName = value;
base.WritePostscript();
}
}
}
#region Command
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
// Using a DependencyProperty as the backing store for Command. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register("Command", typeof(ICommand), typeof(InteractiveCommand), new UIPropertyMetadata(null));
#endregion
}
インターネットからフェッチする他のコードと同様に、クラス全体を読んで、それが何をするのかを理解しようとすることを強くお勧めします。それをアプリに投げ込むだけではいけません。
今、私たちはできる:
<Button Content="I am a button">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<local:InteractiveCommand Command="{Binding CommandWithEventArgs}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
そして背後にあるコード:
#region CommandWithEventArgs
DelegateCommand<MouseEventArgs> _CommandWithEventArgs;
/// <summary>
/// Exposes <see cref="CommandWithEventArgs(MouseEventArgs)"/>.
/// </summary>
public DelegateCommand<MouseEventArgs> CommandWithEventArgs
{
get { return _CommandWithEventArgs ?? (_CommandWithEventArgs = new DelegateCommand<MouseEventArgs>(CommandWithEventArgs)); }
}
#endregion
public void CommandWithEventArgs(MouseEventArgs param)
{
}
そして、それはラップです;)
EDIT: SilverLightの場合は、代わりに次のコードを使用してください。
public class InteractiveCommand : TriggerAction<DependencyObject>
{
protected override void Invoke(object parameter)
{
if (base.AssociatedObject != null)
{
ICommand command = Command;
if ((command != null) && command.CanExecute(parameter))
{
command.Execute(parameter);
}
}
}
#region Command
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
// Using a DependencyProperty as the backing store for Command. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register("Command", typeof(ICommand), typeof(InteractiveCommand), new UIPropertyMetadata(null));
#endregion
}
ただし、本格的なWPFバージョンを使用するよりも安全性が低いことに注意してください(タイプをチェックせず、凍結された要素でクラッシュする可能性があります)。
InteractiveCommandを試しましたが、問題が発生しました。代わりに、Microsoft.Expression.Interactionsへの参照を設定し、
xmlns:ei="http://schemas.Microsoft.com/expression/2010/interactions"
<i:Interaction.Triggers>
<i:EventTrigger EventName="AppointmentEditing">
<ei:CallMethodAction MethodName="AppointmentEditing" TargetObject="{Binding}" />
</i:EventTrigger>
<i:EventTrigger EventName="ShowDialog">
<ei:CallMethodAction MethodName="ShowDialog" TargetObject="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
...私のUserControlで。
次に、イベントハンドラーをViewModelに配置し、スコープをpublicに設定します。
public void ShowDialog(object sender, ShowDialogEventArgs e) {
}
public void AppointmentEditing(object sender, AppointmentEditingEventArgs e) {
}
これまでのところうまく機能しています。