将命令绑定到事件?

Posted

技术标签:

【中文标题】将命令绑定到事件?【英文标题】:Binding Commands to Events? 【发布时间】:2010-10-30 16:14:47 【问题描述】:

将命令绑定到事件的好方法是什么?在我的 WPF 应用程序中,我想通过 ViewModel 捕获和处理一些事件,但我不确定如何。诸如失去焦点、鼠标悬停、鼠标移动等问题。由于我试图遵守 MVVM 模式,我想知道是否有纯 XAML 解决方案。

谢谢!

【问题讨论】:

【参考方案1】:

使用System.Windows.Interactivity

…xmlns:i=http://schemas.microsoft.com/expression/2010/interactivity…

<Slider    
    <i:Interaction.Triggers>    
        <i:EventTrigger EventName="ValueChanged">
            <i:InvokeCommandAction    
                Command="Binding MyCommand"    
                CommandParameter="Binding Text, ElementName=textBox"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Slider>

确保您的项目引用程序集 System.Windows.Interactivity。

来源:MSDN Blog Executing a command from an event of your choice

[更新] 查看Microsoft.Xaml.Behaviors.Wpf(自 2018 年 12 月 3 日起可用)Microsoft 官方包。

【讨论】:

有趣的事实:这也检查了CanExecute【参考方案2】:

看看 Marlon Grech 的 Attached Command Behaviour,它可能正是您要找的东西

【讨论】:

我不会使用整个库,但理论绝对是我正在寻找的。​​span> 【参考方案3】:

为了处理事件,您必须有一些代码将自身附加到事件并执行您的命令作为响应。最终目标是在 XAML 中拥有:

  MouseMoveCommand="Binding MyCommand"

为了实现这一点,您需要为要处理的每个事件定义一个附加属性。有关执行此操作的示例和框架,请参见 this。

【讨论】:

【参考方案4】:

我使用附加属性和反射来实现它。我不能说这是最好的实现,但我可能会改进它,这对你来说可能是一个好的开始。

public class EventBinding : DependencyObject

    public static string GetEventName(DependencyObject obj)
    
        return (string)obj.GetValue(EventNameProperty);
    

    public static void SetEventName(DependencyObject obj, string value)
    
        obj.SetValue(EventNameProperty, value);
        var eventInfo = obj.GetType().GetEvent(value);
        var eventHandlerType = eventInfo.EventHandlerType;
        var eventHandlerMethod = typeof(EventBinding).
            GetMethod("EventHandlerMethod", BindingFlags.Static | BindingFlags.NonPublic);
        var eventHandlerParameters = eventHandlerType.GetMethod("Invoke").GetParameters();
        var eventArgsParameterType = eventHandlerParameters.
            Where(p => typeof(EventArgs).IsAssignableFrom(p.ParameterType)).
            Single().ParameterType;
        eventHandlerMethod = eventHandlerMethod.MakeGenericMethod(eventArgsParameterType);
        eventInfo.AddEventHandler(obj, Delegate.CreateDelegate(eventHandlerType, eventHandlerMethod));
    

    private static void EventHandlerMethod<TEventArgs>(object sender, TEventArgs e)
        where TEventArgs : EventArgs
    
        var command = GetCommand(sender as DependencyObject);
        command.Execute(new EventInfo<TEventArgs>(sender, e));
    

    public static readonly DependencyProperty EventNameProperty = 
        DependencyProperty.RegisterAttached("EventName", typeof(string), typeof(EventHandler));

    public static ICommand GetCommand(DependencyObject obj)
    
        return (ICommand)obj.GetValue(CommandProperty);
    

    public static void SetCommand(DependencyObject obj, ICommand value)
    
        obj.SetValue(CommandProperty, value);
    

    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(EventBinding));



public class EventInfo<TEventArgs>

    public object Sender  get; set; 
    public TEventArgs EventArgs  get; set; 

    public EventInfo(object sender, TEventArgs e)
    
        Sender = sender;
        EventArgs = e;
    


public class EventInfo : EventInfo<EventArgs>

    public EventInfo(object sender, EventArgs e)
        : base(sender, e)  


public class EventBindingCommand<TEventArgs> : RelayCommand<EventInfo<TEventArgs>>
    where TEventArgs : EventArgs

    public EventBindingCommand(EventHandler<TEventArgs> handler)
        : base(info => handler(info.Sender, info.EventArgs))  

使用示例:

查看

<DataGrid local:EventBinding.EventName="CellEditEnding"
          local:EventBinding.Command="Binding CellEditEndingCommand" />

型号

private EventBindingCommand<DataGridCellEditEndingEventArgs> _cellEditEndingCommand;

public EventBindingCommand<DataGridCellEditEndingEventArgs> CellEditEndingCommand

    get 
     
        return _cellEditEndingCommand ?? (
            _cellEditEndingCommand = new EventBindingCommand<DataGridCellEditEndingEventArgs>(CellEditEndingHandler)); 
    


public void CellEditEndingHandler(object sender, DataGridCellEditEndingEventArgs e)

    MessageBox.Show("Test");

【讨论】:

【参考方案5】:

我认为您不能在纯 XAML 中使用它,但请查看 Delegate Command。

【讨论】:

【参考方案6】:

Execute Command, Navigate Frame, and Delegating Command 行为是一个非常好的模式。它也可以在 Expression Blend 中使用。

在“最佳实践”方面,您应该在将事件转换为命令之前三思而后行。通常,命令是用户有意执行的操作,事件通常只是交互轨迹,不应离开视图边界。

【讨论】:

以上是关于将命令绑定到事件?的主要内容,如果未能解决你的问题,请参考以下文章

WPF 将 UI 事件绑定到 ViewModel 中的命令

如何将 WPF 中的命令绑定到控件的双击事件处理程序?

如何将WPF中的命令绑定到控件的双击事件处理程序

WPF 事件绑定到 ViewModel(对于非命令类)

为啥命令绑定到按钮或声明时执行的事件?

为啥命令绑定到按钮或声明时执行的事件?