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

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

谢谢!

【问题讨论】:

    标签: c# wpf xaml mvvm


    【解决方案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 中使用。

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-06-11
            • 2014-11-06
            • 2014-12-02
            • 2018-01-19
            • 2011-11-03
            • 2014-11-04
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多