C# 将命令绑定到事件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/939388/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 03:48:12  来源:igfitidea点击:

Binding Commands to Events?

c#wpfxamlmvvm

提问by djcouchycouch

What's a good method to bind Commands to Events? In my WPF app, there are events that I'd like to capture and process by my ViewModel but I'm not sure how. Things like losing focus, mouseover, mousemove, etc. Since I'm trying to adhere to the MVVM pattern, I'm wondering if there's a pure XAML solution.

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

Thanks!

谢谢!

采纳答案by Thomas Levesque

Have a look at Marlon Grech's Attached Command Behaviour, it could be exactly what you're looking for

看看 Marlon Grech 的附加命令行为,它可能正是您正在寻找的

回答by Gerrie Schenck

I don't think you can use it in pure XAML, but take a look at the Delegate Command.

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

回答by Bojan Resnik

In order to handle events, you must have some code that attaches itself to the event and executes your command in response. The final goal is to have in XAML:

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

  MouseMoveCommand="{Binding MyCommand}"

In order to achieve this you need to define an attached property for each event that you want to handle. See thisfor an example and a framework for doing this.

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

回答by Sergey Aldoukhov

Execute Command, Navigate Frame, and Delegating Commandbehaviour is a pretty good pattern. It is also can be used in the Expression Blend.

Execute Command、Navigate Frame 和 Delegating Command行为是一个非常好的模式。它也可以用于 Expression Blend。

On the "best practices" side, you should think twice before converting an event to a command. Normally, command is something user does intentionaly, an event most often is just an interaction trail, and should not leave the view boundaries.

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

回答by Yuri

I implemented it using Attached Properties and Reflection. I cannot say it is the best implementation, but I will maybe improve it and it may be a good start for you.

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

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)) { }
}

Examples of usage:

用法示例:

View

看法

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

Model

模型

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

回答by kux

Use System.Windows.Interactivity

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

Make sure your project references the assembly System.Windows.Interactivity.

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

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

来源:MSDN 博客从您选择的事件中执行命令

[Update]Have a look to to Microsoft.Xaml.Behaviors.Wpf(available since 03.12.2018) Official package by Microsoft.

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