在MVVM架构下,把EventArgs绑定到Command上

    技术2022-05-19  23

     在使用MVVM架构时,我们会遇到各种各样的问题

      其中一个很常见的问题就是如何在ViewModel层处理UI事件时在后台代码文件中不写任何代码。

      在我这个例子中实现的是取得鼠标移动时的位置。

      我的解决方法如下:

      1、通过一个Behavior 取得关联对象的EventArgs,代码如下

     1  public   class  ExtendedInvokeCommandAction : TriggerAction < FrameworkElement >  2      {  3           public   static   readonly  DependencyProperty CommandProperty  =  DependencyProperty.Register( " Command " typeof (ICommand),  typeof (ExtendedInvokeCommandAction),  new  PropertyMetadata( null , CommandChangedCallback));  4           public   static   readonly  DependencyProperty CommandParameterProperty  =  DependencyProperty.Register( " CommandParameter " typeof ( object ),  typeof (ExtendedInvokeCommandAction),  new  PropertyMetadata( null , CommandParameterChangedCallback));  5   6           private   static   void  CommandParameterChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)  7          {  8              var invokeCommand  =  d  as  ExtendedInvokeCommandAction;  9               if  (invokeCommand  !=   null ) 10                  invokeCommand.SetValue(CommandParameterProperty, e.NewValue); 11          } 12  13           private   static   void  CommandChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) 14          { 15              var invokeCommand  =  d  as  ExtendedInvokeCommandAction; 16               if  (invokeCommand  !=   null ) 17                  invokeCommand.SetValue(CommandProperty, e.NewValue); 18          } 19  20           protected   override   void  Invoke( object  parameter) 21          { 22               if  ( this .Command  ==   null ) 23                   return ; 24  25               if  ( this .Command.CanExecute(parameter)) 26              { 27                  var commandParameter  =   new  ExtendedCommandParameter(parameter  as  EventArgs,  this .AssociatedObject, 28                                                                      GetValue(CommandParameterProperty)); 29                   this .Command.Execute(commandParameter); 30              } 31          } 32  33           #region  public properties 34  35           public   object  CommandParameter 36          { 37               get  {  return  GetValue(CommandParameterProperty); } 38               set  { SetValue(CommandParameterProperty, value); } 39          } 40  41           public  ICommand Command 42          { 43               get  {  return  GetValue(CommandProperty)  as  ICommand; } 44               set  { SetValue(CommandParameterProperty, value); } 45          } 46  47           #endregion 48      }

     

      2、写一个类,包含的属性有事件源、EventArgs和对象,代码如下

     1  public   class  ExtendedCommandParameter  2      {  3           public  ExtendedCommandParameter(EventArgs eventArgs, FrameworkElement sender,  object  parameter)  4          {  5              EventArgs  =  eventArgs;  6              Sender  =  sender;  7              Parameter  =  parameter;  8          }  9  10           public  EventArgs EventArgs {  get private   set ; } 11           public  FrameworkElement Sender {  get private   set ; } 12           public   object  Parameter {  get private   set ; } 13      }

     

      3、为对象添加Behavior

      在我的这个例子中,我对Rectangle添加新建的类ExtendedInvokeCommandAction(即Behavior)

      4、在ViewModel层把这个Behavior绑定到Command上,在这Command上选择一个事件,通过Comman调用这个事件

      在我这个例子中,在ViewModle层我把MouseMove事件绑定到MouseMoved Command上,另外,如果需要的话,可以把任何对象绑定到CommandParameter,在我这个例子中,我把此View(变量名为userControl)绑定到了CommandParameter(不是必须的)

      

     1   2  < Rectangle Fill = " #FF9B9BC5 "  Height = " 200 "  Stroke = " Black "  Width = " 200 " >  3               < i:Interaction.Triggers >  4                   < i:EventTrigger EventName = " MouseMove " >  5                       < local:ExtendedInvokeCommandAction  6                      Command = " {Binding MouseMoved} "  7                      CommandParameter = " {Binding ElementName=userControl} " />  8                   </ i:EventTrigger >  9               </ i:Interaction.Triggers > 10           </ Rectangle > 11 

     

      5、在ViewModel层处理事件,代码如下

     

     1  public   class  MainPageViewModel : INotifyPropertyChanged  2      {  3           public  MainPageViewModel()  4          {  5              MouseMoved  =   new  MainPageCommand( this );  // initialize the Command  6          }  7   8           // gets the position of the mouse  9           private   void  OnMouseMove(ExtendedCommandParameter commandParameter) 10          { 11              MouseEventArgs eventArgs; 12  13               // cast the EventArgs to the type you expect, according to the event you handle 14               // f.e. MouseMove Event  gets you MouseEventArgs 15               //      Click Event gets you RoutedEventArgs 16               if  (commandParameter.EventArgs.GetType()  ==   typeof (MouseEventArgs)) 17              { 18                  eventArgs  =  commandParameter.EventArgs  as  MouseEventArgs; 19                   if  (commandParameter.Parameter  !=   null ) 20                  { 21                      var view  =  commandParameter.Parameter  as  UIElement; 22                      MousePosition  =  eventArgs.GetPosition(view).ToString(); 23                  } 24              } 25          } 26  27           public  MainPageCommand MouseMoved {  get set ; } 28           private   string  _mousePosition; 29           public   string  MousePosition 30          { 31               get  {  return  _mousePosition; } 32               set  { _mousePosition  =  value; OnPropertyChanged( " MousePosition " ); } 33          } 34  35           #region  INotifyChanged Members 36  37           public   event  PropertyChangedEventHandler PropertyChanged; 38           internal   void  OnPropertyChanged( string  propertyName) 39          { 40               if  ( this .PropertyChanged  !=   null ) 41              { 42                   this .PropertyChanged( this new  PropertyChangedEventArgs(propertyName)); 43              } 44          } 45  46           #endregion 47  48           #region  command class 49  50           public   class  MainPageCommand : ICommand 51          { 52               public  MainPageCommand(MainPageViewModel view) 53              { 54                  _view  =  view; 55              } 56  57               private  MainPageViewModel _view; 58  59               #region  ICommand Members 60  61               public   bool  CanExecute( object  parameter) 62              { 63                   return   true ; 64              } 65  66               public   event  EventHandler CanExecuteChanged; 67  68               public   void  Execute( object  parameter) 69              { 70                   // call the method to handle the event 71                  _view.OnMouseMove(parameter  as  ExtendedCommandParameter); 72              } 73  74               #endregion 75  76          } 77       #endregion 78  79      }

      如果需要,可以为每一个EventArgs建一个Behavior,只要把它绑定到Command上,然后Command代码中处理EventArgs就可以了

      代码下载


    最新回复(0)