将命令绑定到事件?

时间:2009-06-02 13:05:54

标签: c# wpf xaml mvvm

将命令绑定到事件的好方法是什么?在我的WPF应用程序中,有些事件我想通过我的ViewModel捕获和处理,但我不确定如何。失去焦点,鼠标悬停,鼠标移动等等。因为我正在努力坚持MVVM模式,我想知道是否有纯XAML解决方案。

谢谢!

6 个答案:

答案 0 :(得分:7)

看一下Marlon Grech的Attached Command Behaviour,它可能正是你想要的

答案 1 :(得分:5)

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

  MouseMoveCommand="{Binding MyCommand}"

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

答案 2 :(得分:5)

使用 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

答案 3 :(得分:2)

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

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");
}

答案 4 :(得分:0)

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

答案 5 :(得分:0)

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

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