MVVM模式的3种command总结

查了不少资料,大概理清楚的就是有3种。当然类名可以自己取了,不过为了便于记忆和区分,还是和看到的文章里面用一样的类名。

1.DelegateCommand

2.RelayCommand

3.AttachbehaviorCommand

因为MVVM模式适合于WPF和SL,所以这3种模式中也有一些小差异,比如RelayCommand下面的CommandManager方法就是WPF下面的,SL下面无法使用,不过我认为这3种方法中的基本思路都如出一辙,都是出自那位外国牛人的文章里面。主要的区别在于和VIEW中的控件的绑定使用上。有点不同的attachbehaviorcommand是prism4里面的一种设计模式,这个区别有点大。但我自己觉得最方便的还是这个DelegateCommand。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/// <summary>
     /// Delegatecommand,这种WPF.SL都可以用,VIEW里面直接使用INTERACTION的trigger激发。比较靠谱,适合不同的UIElement控件
     /// </summary>
     public class DelegateCommand : ICommand
     {
         Func<object, bool> canExecute;
         Action<object> executeAction;
         bool canExecuteCache;
  
         public DelegateCommand(Action<object> executeAction, Func<object, bool> canExecute)
         {
             this.executeAction = executeAction;
             this.canExecute = canExecute;
         }
  
         #region ICommand Members
  
         public bool CanExecute(object parameter)
         {
             bool temp = canExecute(parameter);
  
             if (canExecuteCache != temp)
             {
                 canExecuteCache = temp;
                 if (CanExecuteChanged != null)
                 {
                     CanExecuteChanged(this, new EventArgs());
                 }
             }
  
             return canExecuteCache;
         }
  
         public event EventHandler CanExecuteChanged;
  
         public void Execute(object parameter)
         {
             executeAction(parameter);
         }
  
         #endregion
     }

这个类大概可以这样来理解,构造函数中的action和func,action负责判断是否执行这个command,action就是触发这个command之后要执行的方法。这样理解最浅显,但对刚熟悉command的我来讲,这样最方便记忆和学习,为了使用ICommand接口实现的方法和事件的解释搜搜就可以找到,但是刚开始理解起来还是有点晦涩。

下面是VM里面用这个command的例子。绑定了一个button控件,最简单例子。cm1Click就是构造函数里面的fuc,负责执行响应事件的方法。Cancm1Click就是构造函数里面的action,负责判断这个Command的响应事件是否执行,这里没有用到判断式,直接赋了一个true.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class TestViewModels:INotifyPropertyChanged
 {
         public TestViewModels()
         {
             ......
             cm1click = new DelegateCommand(cm1Click,Cancm1Click);   //初始化delegatecommand
  
         }
        ....
  
        //DelegateCommand
  
         #region command1
  
         public ICommand cm1click { get; set; }
         public void cm1Click(object param)
         {
             MessageBox.Show("CM1 clicked!");
         }
  
         private bool Cancm1Click(object param)
         {
             return true;
         }
  
         #endregion command1
        ......
 }

在XAML里面,用interaction来绑定这个事件,而不是在button里面用command来绑定,这样做有个好处,就是非常直观,并且可以响应其他的很多事件

1
2
3
4
5
6
7
<Button x:Name="BTN_CM1" Content="DelegateCommand" Height="115" Width="148" >
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <i:InvokeCommandAction Command="{Binding cm1click}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>

RelayCommand本来是WPF下面用的一种自定义的command,主要是它用到了事件管理函数,这个SL下面是没有的。不过这部分代码如果修改一下,也可以在SL下面使用,和WPF下面的实现思路差不多。
先看下RelayCommand的定义,一共有2种。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public class RelayCommand<T> : ICommand
     {
         public RelayCommand(Action<T> execute)
             : this(execute, null)
         {
         }
  
         public RelayCommand(Action<T> execute, Predicate<T> canExecute)
         {
             if (execute == null)
                 throw new ArgumentNullException("execute");
  
             _execute = execute;
             _canExecute = canExecute;
         }
  
         [DebuggerStepThrough]
         public bool CanExecute(object parameter)
         {
             return _canExecute == null ? true : _canExecute((T)parameter);
         }
         public event EventHandler CanExecuteChanged
         {
             add{}
             remove{}
             //add
             //{
             //    if (_canExecute != null)
             //        CommandManager.RequerySuggested += value;
             //}
             //remove
             //{
             //    if (_canExecute != null)
             //        CommandManager.RequerySuggested -= value;
             //}
         }
  
         public void Execute(object parameter)
         {
             _execute((T)parameter);
         }
  
         readonly Action<T> _execute = null;
         readonly Predicate<T> _canExecute = null;
  
         bool ICommand.CanExecute(object parameter)
         {
             throw new NotImplementedException();
         }
  
         event EventHandler ICommand.CanExecuteChanged
         {
             add { throw new NotImplementedException(); }
             remove { throw new NotImplementedException(); }
         }
  
         void ICommand.Execute(object parameter)
         {
             throw new NotImplementedException();
         }
     }

第一种是采用泛型的Relaycommand定义,这个泛型到底用在哪里还暂时没看明白。

第二种就是最常用的定义,可以看到在CanExecuteChanged事件里面把commmandmanager方法给注释掉了,就可以在SL下面使用这个类,而且现在看好像也没有什么问题。
在代码上看,Relaycommand和delegatcommand基本上没有啥区别,也是实现了func和action两个参数的办法,基本思路一样。
它们最大的区别就是在前端的调用方式上。delegatecommand使用了expression的SDK里面的interaction来绑定事件,而这种就是直接通过buttonbase的command属性来绑定,因此只能执行单击事件,所以使用范围比较局限,不过如果用interaction来绑定事件的话,其实实现就和delegatecommand一样了。不过为了总结下学习,还是分开来区别下。
前端XAML的代码

后台

是不是和delegatecommand很类似?其实就差不多一样的,基本上就是变个类名而已。不过2个类看到的地方不一样,而且前端绑定的方法不同,所以就还是写一下。下一篇就看看解决思路完全不同的attachbehavior模式。

posted @ 2012-06-04 00:51  therockthe  阅读(666)  评论(0)    收藏  举报