WPF中的MVVM模式:View与ViewModule的交互个人总结

出处:http://www.cnblogs.com/oliverxgwang/archive/2009/07/28/1532678.html

 

在MVVM模式中,viewer负责向用户展示软件设计意图,以期获得最佳的用户体验。VM则负责实现(一定的)业务逻辑,响应Viewer要求,达到隔离业务逻辑的目的。在实际开发中,两者如何进行交互往往是比较头痛的事情。现将开发中用到的交互方法总结一下:
一、使用Binding Command
    利用Command是最常用的手段,因为在软件设计中,软件功能的触发往往是由一些具有Command属性的控件实现的,比如buttonbase、meumItem。在这里推荐一种比较实用的ICommand,代码如下:
该Command可以在响应命令前通过CanExecute方法判断是否该命令有效。但是这种command只适用于具有Command属性的ElementFrame。如果没有,则不能进行Binding。

  1       public   class  RelayCommand < T >  : ICommand
  2      {
  3           #region  Fields
  4 
  5           readonly  Action < T >  _execute  =   null ;
  6           readonly  Predicate < T >  _canExecute  =   null ;
  7 
  8           #endregion
  9 
 10           #region  Constructors
 11           ///   <summary>
 12           ///  构造函数
 13           ///   </summary>
 14           ///   <param name="execute">  执行逻辑,实际执行函数 </param>
 15             public  RelayCommand(Action < T >  execute)
 16              :  this (execute,  null )
 17          {
 18          }
 19           public  RelayCommand(Action < T >  execute, Predicate < T >  canExecute)
 20          {
 21               if  (execute  ==   null )
 22                   throw   new  ArgumentNullException( " execute " );
 23 
 24              _execute  =  execute;
 25              _canExecute  =  canExecute;
 26          }
 27 
 28           #endregion
 29 
 30           #region  ICommand Members
 31           public   bool  CanExecute( object  parameter)
 32          {
 33               return  _canExecute  ==   null   ?   true  : _canExecute((T)parameter);
 34          }
 35 
 36           public   event  EventHandler CanExecuteChanged
 37          {
 38              add
 39              {
 40                   if  (_canExecute  !=   null )
 41                      CommandManager.RequerySuggested  +=  value;
 42              }
 43              remove
 44              {
 45                   if  (_canExecute  !=   null )
 46                      CommandManager.RequerySuggested  -=  value;
 47              }
 48          }
 49 
 50           public   void  Execute( object  parameter)
 51          {
 52              _execute((T)parameter);
 53          }
 54 
 55           #endregion
 56      }
 57 
 58       ///   <summary>
 59       ///  
 60       ///   </summary>
 61       public   class  RelayCommand : ICommand
 62      {
 63           #region  Fields
 64 
 65           readonly  Action _execute;
 66           readonly  Func < bool >  _canExecute;
 67 
 68           #endregion
 69 
 70           #region  Constructors
 71 
 72           ///   <summary>
 73           ///  构造函数
 74           ///   </summary>
 75           ///   <param name="execute"> 实际执行函数 </param>
 76           public  RelayCommand(Action execute)
 77              :  this (execute,  null )
 78          {
 79          }
 80 
 81           public  RelayCommand(Action execute, Func < bool >  canExecute)
 82          {
 83               if  (execute  ==   null )
 84                   throw   new  ArgumentNullException( " execute " );
 85 
 86              _execute  =  execute;
 87              _canExecute  =  canExecute;
 88          }
 89 
 90           #endregion
 91 
 92           #region  ICommand Members
 93 
 94           public   bool  CanExecute( object  parameter)
 95          {
 96               return  _canExecute  ==   null   ?   true  : _canExecute();
 97          }
 98 
 99           public   event  EventHandler CanExecuteChanged
100          {
101              add
102              {
103                   if  (_canExecute  !=   null )
104                      CommandManager.RequerySuggested  +=  value;
105              }
106              remove
107              {
108                   if  (_canExecute  !=   null )
109                      CommandManager.RequerySuggested  -=  value;
110              }
111          }
112 
113           public   void  Execute( object  parameter)
114          {
115              _execute();
116          }
117 
118           #endregion
119      }
二、使用Binding Property
     绑定属性的方法通常用于实施获取界面某个值的变化,配合Binding的Converter和ValidationRule可以很好的效果,不过在VM中要实现INotifyPropertyChanged,集合通常要实现ObservableCollection<T>。
三、使用Attatch Property
    Attatch方法通常是为了VM能够与V通过binding的方法响应一些非Command的事件,比如WindowClose,OnResized等。实现的主要思路是,自定义一个静态类,该类中定义一个AttatchProperty实现,
在XAML文档中对要施加事件的Element的Style中使用Setter进行设置(类似的方法都行,只要附加该自定义AttatchProperty属性就行)。同时在定义的类中,AttachProperty属性注册附加属性当中的属性原数据响应函数中要将DependencyObject对象的特定事件与你的响应函数进行链接。代码如下:

    <Window.Style>
        
<Style TargetType="{x:Type Window}">
            
<Setter 
            Property
="Host:MainWindowBehavior.OnWindowCloseAction" 
            Value
="{Binding }" 
            
/>
        
</Style>
    
</Window.Style>


        public static readonly DependencyProperty OnWindowCloseActionProperty =
            DependencyProperty.RegisterAttached(
            
"OnWindowCloseAction",
            
typeof(object),
            
typeof(MainWindowBehavior),
            
new UIPropertyMetadata(null, OnHostWindowClose));

        
private static void OnHostWindowClose(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MainWindow mainWindow 
= d as MainWindow;
            
if (null != mainWindow)
                mainWindow.Closed 
+= new EventHandler(mainWindow_Closed);

        }

        
static void mainWindow_Closed(object sender, EventArgs e)
        {
            MainWindow mainWindow 
= sender as MainWindow;
            
if (null != mainWindow)
            {
                MainWindowPresenter tempPresenter 
= mainWindow.DataContext as MainWindowPresenter;
                
if (null != tempPresenter)
                    tempPresenter.Dispose();
            }
        }

写到最后:
  上面三种方法都是本人平时开发过程中经常使用的方法,基本可以满足大部分的需要。如果有进一步的需求,可以关注一下http://caliburn.codeplex.com/。类似于Message.Attach="[Event Click] = [Action Divide]"的形式就可以实现命令的链接了。

你可能感兴趣的:(Module)