zoukankan      html  css  js  c++  java
  • MVVM 事件汇总

    在使用MVVM模式时, 按照模式的规则是尽量不直接使用事件. 所以对于以前一直使用事件模式的同行来说确实有点头疼. 还好微软给我们提供了几种间接使用事件(命令)的方法, 下面我就来看看这几种方法:
    ICommand
    ICommand定义了一个接口, 使用它可以轻松的将实现ICommand的接口的命令绑定到包含命令(Command)的控件上(例如Button.Command), 在.net framework库中实现的这个接口的类不是很多, 我所知道的两个: RoutedCommand 和 RoutedUICommand, 而且这两个使用起来比较麻烦, 在这里我就不谈了, 有兴趣的同行可以研究一下. 那么, 除了上述的两个类以外还有自定义类实现ICommand和Prism的DelegateCommand. 我们先看一下自定义的;
    1. 自定义命令
    MyCommand是实现ICommand接口的一个类. 在Execute方法中我们调用传入的Action(Action包含所要实现的功能的方法), IsEnabledExecute是自定义的一个bool类型, 通过设置该值可以启用(禁用)ICommand所绑定到的控件的启用禁用状态.
        
    1. public class MyCommand : ICommand

    2.      {

    3.          public MyCommand(Action<object> action)

    4.          {

    5.              if (action == null) throw new ArgumentNullException();

    6.              _action = action;

    7.          }

    8.   

    9.          private readonly Action<object> _action;

    10.   

    11.          private bool _isEnabledExecute = true;   //默认为启用状态

    12.          public bool IsEnabledExecute

    13.          {

    14.              get { return _isEnabledExecute; }

    15.              set

    16.              {

    17.                  if (_isEnabledExecute != value)

    18.                  {

    19.                      _isEnabledExecute = value;

    20.                      if (CanExecuteChanged != null)

    21.                      {

    22.                          CanExecuteChanged(this, new EventArgs());

    23.                      }

    24.                  }

    25.              }

    26.          }

    27.   

    28.          #region ICommand 接口

    29.          public event EventHandler CanExecuteChanged;

    30.   

    31.          public bool CanExecute(object parameter)

    32.          {

    33.              return _isEnabledExecute;

    34.          }

    35.   

    36.          public void Execute(object parameter)

    37.          {

    38.              _action(parameter);

    39.          }

    40.          #endregion

    41.      }
    复制代码
    定义好MyCommand后我们就可以使用了, 代码如下:
    1.      public class MvvmEventViewModel
    2.      {

    3.          public MvvmEventViewModel()

    4.          {

    5.              /*自定义命令*/

    6.              MyCommandInstance = new MyCommand(MyCommandMethod);

    7.          }

    8.   

    9.          /*自定义命令*/

    10.          public MyCommand MyCommandInstance { get; private set; }

    11.   

    12.          /*Prism命令*/

    13.          public DelegateCommand<object> MyDelegateCommandInstance
    14.          { get; private set; }

    15.          public bool CanExecute(object parameter)

    16.          {

    17.              return MyDelegateCommandInstance.IsActive;

    18.          }

    19.   

    20.          private void MyCommandMethod(object sender)

    21.          {

    22.              if (sender is string)

    23.              {

    24.                  MessageBox.Show("Hello," + sender.ToString());

    25.              }

    26.          }

    27.      }
    复制代码
    <!--XAML-->  
    1. <Button Width="180"

    2.                     Height="23"

    3.                     Margin="0,0,7,0"

    4.                     Command="{Binding MyCommandInstance}"

    5.                     CommandParameter="MyCommand"

    6.                     Content="MyCommand Button" />

    7.             <ToggleButton Width="180"

    8.                           Height="23"

    9.                           Content="启用/禁用"

    10.                           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类而摒弃自定义类, 因为它可以实现我们需要的功能, 所以就没必要再重造轮子.
        
    1. public class MvvmEventViewModel

    2.     {

    3.         public MvvmEventViewModel()

    4.         {

    5.             /*Prism命令*/

    6.             MyDelegateCommandInstance = new DelegateCommand<object>(MyCommandMethod, CanExecute);

    7.             MyDelegateCommandInstance.IsActive = true;

    8.             MyDelegateCommandInstance.IsActiveChanged += (s, e) =>

    9.             {

    10.                 MyDelegateCommandInstance.RaiseCanExecuteChanged();

    11.             };

    12.         }
    13.         /*Prism命令*/

    14.         public DelegateCommand<object> MyDelegateCommandInstance { get; private set; }

    15.         public bool CanExecute(object parameter)

    16.         {

    17.             return MyDelegateCommandInstance.IsActive;

    18.         }

    19.         private void MyCommandMethod(object sender)

    20.         {

    21.             if (sender is string)

    22.             {

    23.                 MessageBox.Show("Hello," + sender.ToString());

    24.             }

    25.         }

    26.     }
    复制代码
    <!--XAML-->
            
    1.    <Button Width="180"

    2.                     Height="23"

    3.                     Margin="0,0,7,0"

    4.                     Command="{Binding MyDelegateCommandInstance}"

    5.                     CommandParameter="DelegateCommand"

    6.                     Content="DelegateCommand Button" />

    7.             <ToggleButton Width="180"

    8.                           Height="23"

    9.                           Content="启用/禁用"

    10.                           IsChecked="{Binding MyDelegateCommandInstance.IsActive}" />
    复制代码
      2.2.CompositeCommand 命令
    CompositeCommand 命令可以理解为一个命令组. 将ICommand注册到CompositeCommand中, 然后绑定在Command上, 就可以让Command触发注册到CompositeCommand的所有命令.
        2.2.1.定义一个CompositeCommand命令
        
    1. public class Comm

    2.     {

    3.         #region CompositeCommand

    4.         private static CompositeCommand _compositeCommand = new CompositeCommand();

    5.         public static CompositeCommand CompositeCommand

    6.         {

    7.             get { return _compositeCommand; }

    8.         }

    9.         #endregion

    10.     }
    复制代码
        2.2.2.使用CompositeCommand命令

    1. Comm.CompositeCommand.RegisterCommand(MyCommandInstance);
    2. Comm.CompositeCommand.RegisterCommand(MyDelegateCommandInstance);
    3. <!--XAML-->
    4. xmlns:comm="clr-namespace:Blogs.WPF"
    复制代码
          
    1. <Button Width="180"

    2.                 Height="23"

    3.                 Margin="0,0,7,0"

    4.                 HorizontalAlignment="Left"

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

    6.                 CommandParameter="DelegateCommand"

    7.                 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, 现在就让我们就来使用这两个组件, 代码简单, 请看:

    1. public DelegateCommand LostFocusCommand { get; private set; }
    2. LostFocusCommand = new DelegateCommand(LostFocusMethod);

    3. private void LostFocusMethod()
    4. {
    5. MessageBox.Show("捕获到了.嘿牟嘿牟.");
    6. }

    7. <TextBlock Background="OrangeRed" Text="左键按下时我能捕获到">
    8. <i:Interaction.Triggers>
    9. <!-- 当单击鼠标左键按下时 -->
    10. <i:EventTrigger EventName="MouseLeftButtonDown">
    11. <i:InvokeCommandAction Command="{Binding LostFocusCommand}" />
    12. </i:EventTrigger>
    13. </i:Interaction.Triggers>
    14. </TextBlock>
    复制代码


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

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

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

    添加命名空间

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


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

  • 相关阅读:
    【NOIp模拟赛】种花
    【NOIP模拟赛】质数序列
    【NOIp模拟赛】兔子
    【NOIp模拟赛】圆桌游戏
    【NOIp模拟赛】花
    【洛谷P2345】奶牛集会
    【洛谷P1774】最接近神的人_NOI导刊2010提高(02)
    【洛谷P1495】 曹冲养猪
    【洛谷P1287】 盒子与球
    NOIP2009 Hankson 的趣味题
  • 原文地址:https://www.cnblogs.com/swarb/p/9924387.html
Copyright © 2011-2022 走看看