mvvm 事件命令

在使用MVVM模式时, 按照模式的规则是尽量不直接使用事件. 所以对于以前一直使用事件模式的同行来说确实有点头疼. 还好微软给我们提供了几种间接使用事件(命令)的方法, 下面我就来看看这几种方法:

ICommand

ICommand定义了一个接口, 使用它可以轻松的将实现ICommand的接口的命令绑定到包含命令(Command)的控件上(例如Button.Command), 在.net framework库中实现的这个接口的类不是很多, 我所知道的两个: RoutedCommand 和 RoutedUICommand, 而且这两个使用起来比较麻烦, 在这里我就不谈了, 有兴趣的同行可以研究一下. 那么, 除了上述的两个类以外还有自定义类实现ICommand和Prism的DelegateCommand. 我们先看一下自定义的;

1. 自定义命令

MyCommand是实现ICommand接口的一个类. 在Execute方法中我们调用传入的Action(Action包含所要实现的功能的方法), IsEnabledExecute是自定义的一个bool类型, 通过设置该值可以启用(禁用)ICommand所绑定到的控件的启用禁用状态.

View Code
 1      public class MyCommand : ICommand
 2  
 3      {
 4  
 5          public MyCommand(Action<object> action)
 6  
 7          {
 8  
 9              if (action == null) throw new ArgumentNullException();
10  
11              _action = action;
12  
13          }
14  
15   
16  
17          private readonly Action<object> _action;
18  
19   
20  
21          private bool _isEnabledExecute = true;   //默认为启用状态
22  
23          public bool IsEnabledExecute
24  
25          {
26  
27              get { return _isEnabledExecute; }
28  
29              set
30  
31              {
32  
33                  if (_isEnabledExecute != value)
34  
35                  {
36  
37                      _isEnabledExecute = value;
38  
39                      if (CanExecuteChanged != null)
40  
41                      {
42  
43                          CanExecuteChanged(this, new EventArgs());
44  
45                      }
46  
47                  }
48  
49              }
50  
51          }
52  
53   
54  
55          #region ICommand 接口
56  
57          public event EventHandler CanExecuteChanged;
58  
59   
60  
61          public bool CanExecute(object parameter)
62  
63          {
64  
65              return _isEnabledExecute;
66  
67          }
68  
69   
70  
71          public void Execute(object parameter)
72  
73          {
74  
75              _action(parameter);
76  
77          }
78  
79          #endregion
80  
81      }

定义好MyCommand后我们就可以使用了, 代码如下:

View Code
 1      public class MvvmEventViewModel
 2      {
 3  
 4          public MvvmEventViewModel()
 5  
 6          {
 7  
 8              /*自定义命令*/
 9  
10              MyCommandInstance = new MyCommand(MyCommandMethod);
11  
12          }
13  
14   
15  
16          /*自定义命令*/
17  
18          public MyCommand MyCommandInstance { get; private set; }
19  
20   
21  
22          /*Prism命令*/
23  
24          public DelegateCommand<object> MyDelegateCommandInstance 
25          { get; private set; }
26  
27          public bool CanExecute(object parameter)
28  
29          {
30  
31              return MyDelegateCommandInstance.IsActive;
32  
33          }
34  
35   
36  
37          private void MyCommandMethod(object sender)
38  
39          {
40  
41              if (sender is string)
42  
43              {
44  
45                  MessageBox.Show("Hello," + sender.ToString());
46  
47              }
48  
49          }
50  
51      }

<!--XAML-->

View Code
 1 View Code 
 2 
 3             <Button Width="180"
 4 
 5                     Height="23"
 6 
 7                     Margin="0,0,7,0"
 8 
 9                     Command="{Binding MyCommandInstance}"
10 
11                     CommandParameter="MyCommand"
12 
13                     Content="MyCommand Button" />
14 
15             <ToggleButton Width="180"
16 
17                           Height="23"
18 
19                           Content="启用/禁用"
20 
21                           IsChecked="{Binding MyCommandInstance.IsEnabledExecute}" />

首先定义了MvvmEventViewModel, 在MvvmEventViewModel中实例化了MyCommand, 将Button所在的界面或者用户控件的属性DataContext绑定上MvvmEventViewModel的实例, 最后直接在Button的Command属性上绑定MyCommandInstance;

2.prism命令

prism是微软的一个开源框架, 其为WPF(SL)而生, 自然也少不了MVVM模式的一些辅助类, 其中命令就是典型的辅助类. 在上面我们是自定义命令, 其实在prism框架中已经提供了命令类, 那就是DelegateCommand, 该类还为泛型提供了支持; 不仅如此prism还提供了多个命令的绑定CompositeCommand, 为一个Button命令可以执行多个方法问题提供了廉价的解决方案.

2.1. DelegateCommand 命令

DelegateCommand 命令与我们上面自定义的命令一样, 都是可以绑定到Button的Command属性上, 使用该类少了几行代码, 多了一份省心和安全. 如果让我选择我会选择DelegateCommand类而摒弃自定义类, 因为它可以实现我们需要的功能, 所以就没必要再重造轮子.

View Code
 1 View Code 
 2 
 3     public class MvvmEventViewModel
 4 
 5     {
 6 
 7         public MvvmEventViewModel()
 8 
 9         {
10 
11             /*Prism命令*/
12 
13             MyDelegateCommandInstance = new DelegateCommand<object>(MyCommandMethod, CanExecute);
14 
15             MyDelegateCommandInstance.IsActive = true;
16 
17             MyDelegateCommandInstance.IsActiveChanged += (s, e) =>
18 
19             {
20 
21                 MyDelegateCommandInstance.RaiseCanExecuteChanged();
22 
23             };
24 
25         }
26 
27  
28 
29         /*Prism命令*/
30 
31         public DelegateCommand<object> MyDelegateCommandInstance { get; private set; }
32 
33         public bool CanExecute(object parameter)
34 
35         {
36 
37             return MyDelegateCommandInstance.IsActive;
38 
39         }
40 
41  
42 
43         private void MyCommandMethod(object sender)
44 
45         {
46 
47             if (sender is string)
48 
49             {
50 
51                 MessageBox.Show("Hello," + sender.ToString());
52 
53             }
54 
55         }
56 
57     }

<!--XAML-->

View Code
 1             <Button Width="180"
 2 
 3                     Height="23"
 4 
 5                     Margin="0,0,7,0"
 6 
 7                     Command="{Binding MyCommandInstance}"
 8 
 9                     CommandParameter="MyCommand"
10 
11                     Content="MyCommand Button" />
12 
13             <ToggleButton Width="180"
14 
15                           Height="23"
16 
17                           Content="启用/禁用"
18 
19                           IsChecked="{Binding MyCommandInstance.IsEnabledExecute}" />

2.2.CompositeCommand 命令

CompositeCommand 命令可以理解为一个命令组. 将ICommand注册到CompositeCommand中, 然后绑定在Command上, 就可以让Command触发注册到CompositeCommand的所有命令.

2.2.1.定义一个CompositeCommand命令

View Code
 1     public class Comm
 2 
 3     {
 4 
 5         #region CompositeCommand
 6 
 7         private static CompositeCommand _compositeCommand = new CompositeCommand();
 8 
 9         public static CompositeCommand CompositeCommand
10 
11         {
12 
13             get { return _compositeCommand; }
14 
15         }
16 
17         #endregion
18 
19     }

2.2.2.使用CompositeCommand命令

Comm.CompositeCommand.RegisterCommand(MyCommandInstance);

Comm.CompositeCommand.RegisterCommand(MyDelegateCommandInstance);

<!--XAML-->

xmlns:comm="clr-namespace:Blogs.WPF"

复制代码
<Button Width="180"

                Height="23"

                Margin="0,0,7,0"

                HorizontalAlignment="Left"

                Command="{x:Static comm:Comm.CompositeCommand}"

                CommandParameter="DelegateCommand"

                Content="CompositeCommand Button" />
复制代码

将我们刚才定义的两个命令MyCommandInstance和MyDelegateCommandInstance注册到Comm.CompositeCommand中, 然后在一个Button上绑定 comm:Comm.CompositeCommand 此时我们单击CompositeCommand Button时发现触发了两个命令. 同样的我们也可以使用UnregisterCommand卸载命令.

2.3.将其他事件绑定到ICommand上

在上述的例子中我们只是在Button的Command属性上绑定ICommand, 那么对于一些特殊事件(如Loaded, MouseDown, MouseUp)我们该怎么处理呢? 网上也有一些传统的方法, 将控件直接传送到VM中, 使用+=创建特殊的事件. 其实还有更好的办法, 那就是System.Windows.Interactivity.dll 组件.

在你的项目中引入System.Windows.Interactivity.dll, 然后在页面中添加如下代码: xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

OK, 现在就让我们就来使用这两个组件, 代码简单, 请看:

复制代码
public DelegateCommand LostFocusCommand { get; private set; }
 
LostFocusCommand = new DelegateCommand(LostFocusMethod);
 
 
 
private void LostFocusMethod()
 
{
 
MessageBox.Show("捕获到了.嘿牟嘿牟.");
 
}
复制代码
复制代码
<TextBlock Background="OrangeRed" Text="左键按下时我能捕获到">
 
<i:Interaction.Triggers>
 
<!-- 当单击鼠标左键按下时 -->
 
<i:EventTrigger EventName="MouseLeftButtonDown">
 
<i:InvokeCommandAction Command="{Binding LostFocusCommand}" />
 
</i:EventTrigger>
 
</i:Interaction.Triggers>
 
</TextBlock>
复制代码

注: 名字起的有点不对应. 不想改了, 大家知道就可以.

以上是使用System.Windows.Interactivity.dll组件可以将事件直接绑定到命令上, 但是我觉得这样麻烦, 如果可以直接使用事件岂不是更爽. 呵呵. 能提出问题就能解答问题. 我们再看另一个组件 Microsoft.Expression.Interactions.dll .

同样的, 项目中引用 Microsoft.Expression.Interactions.dll

添加命名空间

复制代码
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
 
<UserControl>
 
<i:Interaction.Triggers>
 
<i:EventTrigger EventName="Loaded">
 
<ei:CallMethodAction MethodName="View_Loaded" TargetObject="{Binding}" />
 
</i:EventTrigger>
 
</i:Interaction.Triggers>
 
</UserControl>
复制代码

注意: 在多层项目中. 只要你使用System.Windows.Interactivity.dll, Microsoft.Expression.Interactions.dll 这两个组件, 就必须在启动层中引用这两个DLL, 否则报错.

原文地址:https://www.cnblogs.com/xiaogui9527/p/2982281.html