Mvvm Light Toolkit for wpf/silverlight系列之Command和Events

转自http://blog.csdn.net/duanzilin/article/details/6399640

事件是WPF/SL应用程序中UI与后台代码进行交互的最主要方式,与传统方式不同,mvvm中主要通过绑定到命令来进行事件的处理,因此要了解mvvm中处理事件的方式,就必须先熟悉命令的工作原理。 

 

一、RelayCommand命令

WPF/SL命令是通过实现 ICommand 接口创建的。 ICommand 公开两个方法(ExecuteCanExecute)和一个事件(CanExecuteChanged)。 Execute 执行与命令关联的操作。CanExecute 确定是否可以在当前命令目标上执行命令。在MvvmLight中实现ICommand接口的类是RelayCommand,RelayCommand通过构造函数初始化Execute 和 CanExecute方法,因此,构造函数传入的是委托类型的参数,Execute 和 CanExecute则执行的是委托的方法,RelayCommand相关代码如下:

[c-sharp:collapse] + expand sourceview plaincopy

 

二、 Comand属性绑定

通常实现了 ICommandSource的控件可以使用Comand属性绑定,实现 ICommandSource 的 WPF 类包括:ButtonBaseMenuItemHyperlink 以及 InputBinding

简单绑定示例:

xaml:

[xhtml] view plaincopy

  1. <Button Command="{Binding SimpleCommand}" Content="简单命令" />  

 
ViewModel:

[c-sharp] view plaincopy

  1. public MainViewModel()  
  2. {  
  3.      ...  
  4.   
  5.        SimpleCommand = new RelayCommand  
  6.         (  
  7.             () => CommandResult = "执行简单命令"  
  8.         );  

注意:SL4才开始支持Command属性绑定,之前的版本不能使用Command属性绑定

CanExecute命令绑定示例:

xaml:

 

[xhtml] view plaincopy

  1. <Button Command="{Binding CanExecuteCommand}" Content="CanExecute命令" Margin="5,0,5,0"/>  
  2. <CheckBox x:Name="chkCanClick" IsChecked="{Binding CanClick,Mode=TwoWay}"   
  3.           Content="勾上复选框,CanExecute命令按钮才能变为可用"/>  

viewmodel:

[c-sharp] view plaincopy

  1. bool _CanClick;  
  2. public bool CanClick  
  3. {  
  4.     get { return _CanClick; }  
  5.   
  6.     set  
  7.     {  
  8.         if (_CanClick == value)  
  9.             return;  
  10.   
  11.         _CanClick = value;  
  12.   
  13.         RaisePropertyChanged("CanClick");  
  14.           
  15.         // SL中需要手动调用RaiseCanExecuteChanged方法更新按钮可用s状态  
  16.         CanExecuteCommand.RaiseCanExecuteChanged();  
  17.   
  18.     }  
  19. }  
  20.   
  21. public MainViewModel()  
  22. {  
  23.     ...  
  24.   
  25.     CanExecuteCommand = new RelayCommand  
  26.        (  
  27.            () =>  
  28.            {  
  29.                CommandResult = "执行CanExecute命令";  
  30.            },  
  31.            () => CanClick  // 等价于()=>{return CanClick;}  
  32.        );  
  33.        ...  
  34. }  

与简单命令绑定不同的 是,CanExecuteCommand构造函数包含两个参数,第二个参数的返回值表示是否可以在按钮上执行命令操作,返回False,则不能在按钮上执 行命令,因此按钮为不可用,返回True,则能够在按钮上执行命令,按钮可用。以上示例中,CanExecute返回值与CheckBox的 IsChecked属性关联,这样更改CheckBox的勾选状态,按钮的可用状态会随之更改。

 

带参数的命令绑定示例:

xaml:

[xhtml] view plaincopy

  1. <Button Command="{Binding ParamCommand}" Content="带参数的CanExecute命令"  
  2.         CommandParameter="{Binding CanClick,Mode=OneWay}" Margin="5,0,5,0"/>  

viewmodel:

[c-sharp] view plaincopy

  1. public MainViewModel()  
  2. {  
  3.      ...  
  4.   
  5.      ParamCommand = new RelayCommand<bool?>  
  6.         (  
  7.             (p) =>  
  8.             {  
  9.                 CommandResult = string.Format("执行带参数的命令(参数值:{0})", p);  
  10.             },  
  11.             (p) => p??false  
  12.         );  
  13.      ...  
  14. }  

这里ParamCommand接收TextBox的值作为参数,泛型版本表示参数类型为string,此时Execute和CanExecute参数也必须是带参数的版本。

 

注意:

   1、在SL4中带参 数的CanExecute与不带参数的CanExecute之间的区别;带参数的CanExecute,与参数绑定的属性(CanClick)更改,会自 动触发命令的CanExecute方法,而不带参数的CanExecute方法,则需要手动调用 CanExecuteCommand.RaiseCanExecuteChanged()方法更新按钮的可用状态。

 2、在WPF中,RelayCommand通过CommandManager不停地侦听按钮的CanExecute的状态,因此WPF中按钮的CanExecute状态会随时响应CanExecute方法中的更改,WPF中可以不调用命令的RaiseCanExecuteChanged方法

 

      三、使用行为绑定命令

Command属性绑定只能绑定ICommandSource类型的控件的点击事件,对于其他控件事件,比如TextChanged事件,不能直接绑定到Command,这时我们可以使用Blend的InvokeCommandAction行为来绑定事件到命令,使用步骤如下:

用Blend4打开解决方案,选中要触发事件的控件,比如TextBox,在资产面板中选择行为,在列表中选择InvokeCommandAction,如图:

 

 双击InvokeCommandAction后会为TextBox生成InvokeCommandAction行为,在属性栏可以设置行为的属性:

在EventName栏选择触发的事件名称TextChanged,Command绑定跟Button的绑定方式一样,最后我们生成的代码如下:

xaml:

 

[xhtml] view plaincopy

  1. <TextBox x:Name="TextBox1" Margin="5,0,5,0" Width="100">  
  2.   <i:Interaction.Triggers>  
  3.     <i:EventTrigger EventName="TextChanged">  
  4.       <i:InvokeCommandAction Command="{Binding BehaviourCommand, Mode=OneWay}"  
  5.                              CommandParameter="{Binding Text,ElementName=TextBox1}"/>  
  6.     </i:EventTrigger>  
  7.   </i:Interaction.Triggers>  
  8. </TextBox>  

ViewModel:

[c-sharp] view plaincopy

  1. public MainViewModel()  
  2. {  
  3.     ...  
  4.   
  5.     BehaviourCommand = new RelayCommand<string>  
  6.        (  
  7.            (p) =>  
  8.            {  
  9.                CommandResult = string.Format("执行TextChanged命令,触发命令的TextBox值为{0}",p);  
  10.            },  
  11.            (p) =>   
  12.            {   
  13.                return !string.IsNullOrEmpty(p);   
  14.            }  
  15.        );  
  16.     ...  
  17. }  

这样就可以间接的将TextBox的MouseRightButtonDown事件绑定到Command。

注意:

这种方式相当于将事件映射到Command,CanExecute的返回值只能决定命令是否会被执行,而不能是使得命令目标的可用状态发生改变。以上示例中,输入第一个字母时,命令并没有执行,此时命令无效,但文本框仍然有效,输入第二个字母命令才执行

 

四、使用MvvmLight行为EventToCommand绑定命令

虽然InvokeCommandAction行为可以将控件的事件转换到Command绑 定,也可以通过CommandParameter向ViewModel传递参数,但是对于一些特殊的事件,比如MouseMove,我们需要在事件处理方 法中得到鼠标位置信息,使用上面的方式仍不能完成任务;这时我们就需要使用EventToCommand行为,它是MvvmLight封装的行为,要使用 行为需要添加GalaSoft.MvvmLight.Extras.dll和System.Windows.Interactivity.dll的引用。

同样,在Blend4中打开解决方案,选中要触发事件的控件 ,在资产面板中选择行为,在 列表中选择EventToCommand,双击生成行为,然后设置EventName为MouseMove,然后设置Command绑定,同时需要设置 PassEventArgsToCommand="True",也就是将事件参数传递给Command,生成的代码如下:

xaml:

[xhtml] view plaincopy

  1. <Grid>  
  2.         <Ellipse Fill="AliceBlue" Height="180" Stroke="Black" Margin="10,8">  
  3.         <i:Interaction.Triggers>  
  4.           <i:EventTrigger EventName="MouseMove">  
  5.             <GalaSoft_MvvmLight_Command:EventToCommand PassEventArgsToCommand="True"  
  6.                                             Command="{Binding MoveMouseCommand}" />  
  7.           </i:EventTrigger>  
  8.         </i:Interaction.Triggers>  
  9.       </Ellipse>  
  10.   
  11.       <TextBlock HorizontalAlignment="Center" Text="带事件参数的命令 (鼠标移动事件)"  
  12.                  TextWrapping="Wrap" Grid.Row="7" d:LayoutOverrides="Height"  
  13.                  Grid.ColumnSpan="2" VerticalAlignment="Center"  
  14.                  FontSize="20" FontWeight="Bold"  
  15.                  IsHitTestVisible="False" />  
  16.     </Grid>  

viewmodel:

[c-sharp] view plaincopy

  1. MoveMouseCommand = new RelayCommand<MouseEventArgs>  
  2.     (  
  3.         (e) =>   
  4.             {  
  5.                 var element = e.OriginalSource as UIElement;  
  6.                 var point = e.GetPosition(element);  
  7.   
  8.                 CommandResult = string.Format("执行带MouseEventArgs事件参数的命令,鼠标位置:X-{0},Y-{1}",point.X,point.Y);  
  9.             }  
  10.     );  

这里命令的初始化方式与带参数的命令一样,只需将参数类型换成事件参数类型

 

EventToCommand不仅可以用来传递事件参数,他还可以将CanExecute返回值与命令目标的IsEnable属性关联,我们只需将MustToggleIsEnabled的属性设置为True就可以了,示例代码如下:

xaml:

[xhtml] view plaincopy

  1. <TextBox x:Name="TextBox2" Text="为空时CanExecute为false" Margin="5,0,5,0" Width="200">  
  2.         <i:Interaction.Triggers>  
  3.           <i:EventTrigger EventName="TextChanged">  
  4.             <GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding BehaviourCommand}"  
  5.                                                        MustToggleIsEnabled="{Binding IsChecked,ElementName=chkMustToggle}"    
  6.                                                        CommandParameter="{Binding Text,ElementName=TextBox2}" />  
  7.           </i:EventTrigger>  
  8.         </i:Interaction.Triggers>  
  9.       </TextBox>  
  10.       <CheckBox x:Name="chkMustToggle" IsChecked="False" Content="MustToggleIsEnabled,勾选则TextBox的可用状态与CanExecute返回值关联"/>  

 

五、使用自定义行为绑定命令

如果以上方法都不能满足你的要求,你还可以自定义行为来绑定命令,以下是WPF中自定义行为的代码(SL代码请在文章最后下载示例代码对照阅读):

首先,我们创建一个命令参数类型:

[c-sharp:collapse] + expand sourceview plaincopy

然后创建行为类:

[c-sharp:collapse] + expand sourceview plaincopy

编译生成项目,在Blend4中打开解决方案,选中要触发事件的控件 ,在资产面板中选择行为,在列表中选择MapRoutedEventToCommand ,双击生成行为,然后设置EventName为TextChanged,然后设置Command绑定,代码如下:

xaml:

[xhtml] view plaincopy

  1. <TextBox x:Name="TextBox3" Text="更改文本框的值" Margin="5,0,5,0" Width="200">  
  2.   <i:Interaction.Triggers>  
  3.     <i:EventTrigger EventName="TextChanged">  
  4.       <my:MapRoutedEventToCommand Command="{Binding CustomBehaviorCommand}" CommandParameter="P1"/>  
  5.     </i:EventTrigger>  
  6.   </i:Interaction.Triggers>  
  7. </TextBox>  

viewmodel:

[c-sharp] view plaincopy

  1. CustomBehaviorCommand = new RelayCommand<EventInformation<RoutedEventArgs>>  
  2.    (  
  3.        (ei) =>  
  4.        {  
  5.            EventInformation<RoutedEventArgs> eventInfo = ei as EventInformation<RoutedEventArgs>;  
  6.   
  7.            System.Windows.Controls.TextBox sender = eventInfo.Sender as System.Windows.Controls.TextBox;  
  8.   
  9.            CommandResult = string.Format("执行{0}的TextChanged命令,文本框的值:{1},传递的参数:{2},事件参数:{3}",  
  10.                sender.Name,  
  11.                sender.Text,  
  12.                ei.CommandArgument,  
  13.                ei.EventArgs.GetType().ToString());  
  14.        },  
  15.        (ei) =>  
  16.        {  
  17.            return true;  
  18.        }  
  19.    );  

这样,我们就可以同时将sender、CommandParameter、和事件参数传递到Command的参数中了

 

本章节主要介绍MvvmLight中命令和事件的处理方法,下章我们将介绍MvvmLight中的Messenger的使用方法,以下是本章源代码下载:

 

http://download.csdn.net/source/3262832

 

时间: 2024-09-14 09:30:29

Mvvm Light Toolkit for wpf/silverlight系列之Command和Events的相关文章

Silverlight实用窍门系列:52.Silverlight中的MVVM框架极速入门(以MVVM Light Toolkit为例)

 在本文将以MVVM Light Toolkit为例讲解MVVM框架在现实中的使用入门,首先我们在http://mvvmlight.codeplex.com/下载它的MVVM框架下来.也可以通过 http://files.cnblogs.com/chengxingliang/GalaSoft.MvvmLight.V3.rar 下载MVVM Light Toolkit.然后我们安装这个安装包,然后重新打开VS2010,新建一个项目,如下图所示:    Tip:MVVM分为Model.ViewMod

WPF基础到企业应用系列7深入剖析依赖属性(WPF/Silverlight核心)

一. 摘要 首先圣殿骑士很高兴这个系列能得到大家的关注和支持,这个系列从七月份开始到现在才第七篇,上一篇发布是在8月2日,掐指一算有二十多天没有继续更新了,最主要原因一来是想把它写好,二来是因为最近几个月在筹备"云计算之旅"系列,所以一再推迟了发布进度.之前一直都没有想过要录制视频,主要的原因还是怕自己知识有限,从而误导他人,所以前几次浪曦和51CTO邀请录制视频,我都以工作忙.公司内部培训需要时间和自己有待提高等理由委婉的拒绝了,说实在的,自己也知道自己还有很多地方有待提高,还需要向

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十五)

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十五)制作精美的可任意拖放对象的物品栏及装备栏 在通常的网络游戏中,物品.装备.技能.快捷按钮等窗口中的图标都是可以相互拖放的,不同的栏目有着不同的限制,例如技能图标不能拖放到物品栏及装备栏中,且不是所有的魔法技能都可以拖放(如被动技能等):而非装备类的所有物品则无法拖放到角色的装备栏中.那么本节我将向大家讲解如何在本教程示例游戏中添加物品栏及装备栏,并实现它们之间双向物品交换的两种模式:拖放模式和双击模

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(三十二)

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(三十二) 雷.混.冰.毒.火.风 - 幻化中的魔法魅力 本节,我将为大家演示如何为游戏中的魔法增加华丽的附加属性. 第一步,定义规则: 1)定义魔法附加属性分类:在本教程示例游戏中,我将魔法附加属性定义为6类:雷.混.冰.毒.火.风,为什么要以这样无规律的方式去命名?因为是教程,我们需要学习的是如何实现对应效果,此6类属性算是目前网游中最流行的六大魔法属性,如果大家都掌握了,无论是中国式5行还是诸如其他的风格设

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十四)

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十四)制作主角属性面板及加点器 游戏中会使用大量的菜单面板,而这些面板往往都带有选项卡.如果用Silverlight工具中的TabControl,则需要通过复杂的xaml重写模板来实现自定义样式,这一点时常让开发者头疼,毕竟界面的东西应该属于美工的范畴,这也是我所发现在目前Silverlight中唯一一处只能通过xaml而无法用代码实现的地方.当然,如果您对此特别感兴趣,同样可以到http://www.c

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十三)

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十三)制作游戏主菜单面板及鼠标左右键快捷技能栏 每款MMORPG都有一个主菜单,通常置于窗口的底部.游戏中主角大部分的设置操作都从这里开启.如人物属性.物品(包裹).技能.任务.队伍.地图.家族.门派.商城.系统设置等等:当然,还包括快捷自定义菜单栏,以及类似<暗黑破坏神>中经典式的左右键快捷技能栏.这些内容在不同的游戏中往往会根据自身的特性稍做调整,但整体上大同小异.本节,我将同样以<剑侠世界&

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十二)

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十二)制作精美的Mini地图② 前面章节中讲解的包括对象头像面板.Mini雷达地图等窗体都是位置固定的,在处理起来方式多样且简单:而RPG.SLG.休闲养成等类型的游戏中往往会大量使用到悬浮且可自由拖动的窗体,比如包裹面板.武器装备面板.个人属性面板.技能面板.系统设置面板等等,这就要求我们必须为游戏量身定做一个通用且易用的ChildWindow控件.那么本节我将为大家讲解如何制作一个包含可拖动头部.关闭

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十一)

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十一)制作精美的Mini地图① 用什么来承受未来几个月日思夜想的折磨?除了学习还是学习. 感慨了一翻,嘿嘿.本节我将为大家讲解如何为Silverlight游戏制作一个精美的Mini地图.Mini地图又分两种,一种是通常处于游戏窗口右上角的Mini雷达(导航)地图:另一种是全景Mini寻路地图.本节我先向大家讲解如何制作导航Mini雷达地图.此类地图在游戏中主要起到导航作用,即引导主角前行的方向,并且呈现出

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(十)

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(十)斜度α地图的构造及算法 在当前的网络游戏中,地图基本都是采取一定斜度的拼装地图,这其中存在两种斜度地图的构造方式: 第一种我称之为伪斜度地图:该类型地图表现层图片为斜度的,但地图基底障碍物等的构造则实为正方形,如下图: 其实最典型的例子就是上一节所演示的内容了,地图是斜的,但是我们却用垂直的障碍物对其进行基底布局,这就是典型的伪斜度地图了. 这样的地图优点在于可以使用简单直接的地图构造算法(上一节中有详细的