[Silverlight入门系列]使用MVVM模式(6):使用Behavior

Behavior把一些常用的行为封装成可重复使用的组件(Component)在理想状况下,Designer(设计师)domain expert(特定领域的专家,例如财会人员、HR人员、或MIS)甚至可以完全不需要具备程序设计的观念,只需要了解基础的事件(Event)观念,就可以顺利的开发出一套系统,若需要实现特定的功能时,可商请developere为他们开发所需要的Behaviordesigner只需要取得这些Behavior并使用即可。例如,界面设计人员可以使用Expression Blend把一个Behavior拖到一个界面元素上,比如右键点击以后启动一段动画这个行为,这个界面元素就会自动执行,岂不是很清爽!(当然,执行函数还是要编程人员编写),来个例子:

界面xaml:

View Code
1 < UserControl
2 xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:d ="http://schemas.microsoft.com/expression/blend/2008"
5 xmlns:mc ="http://schemas.openxmlformats.org/markup-compatibility/2006"
6 xmlns:wm ="clr-namespace:AsycValidation"
7 xmlns:i ="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei ="http://schemas.microsoft.com/expression/2010/interactions" x:Class ="AsycValidation.MainPage"
8 mc:Ignorable ="d"
9 x:Name ="MyUserControl"
10 d:DesignHeight ="300" d:DesignWidth ="400" >
11
12 < Grid x:Name ="Layout" >
13 < TextBlock Height ="32" HorizontalAlignment ="Left" Margin ="41,53,0,0" x:Name ="textBlock1" Text ="Company:" VerticalAlignment ="Top" Width ="66" />
14 < TextBox Height ="31" HorizontalAlignment ="Left" Margin ="120,45,0,0" x:Name ="textBox1" Text =" {Binding CompanyName, Mode=TwoWay, NotifyOnValidationError=True} " VerticalAlignment ="Top" Width ="119" />
15 < TextBox Height ="30" HorizontalAlignment ="Left" Margin ="120,104,0,0" x:Name ="textBox2" Text =" {Binding CompanyID, Mode=TwoWay, NotifyOnValidationError=True} " VerticalAlignment ="Top" Width ="119" />
16 < Button Content ="Button" Height ="36" HorizontalAlignment ="Left" Margin ="120,156,0,0" x:Name ="button1" VerticalAlignment ="Top" Width ="81" >
17 < i:Interaction.Triggers >
18 < i:EventTrigger EventName ="Click" >
19 < ei:CallMethodAction MethodName ="button1_Click" TargetObject =" {Binding ElementName=MyUserControl} " />
20 </ i:EventTrigger >
21 < i:EventTrigger >
22 < ei:CallMethodAction MethodName ="button1_loaded" TargetObject =" {Binding ElementName=MyUserControl} " />
23 </ i:EventTrigger >
24 </ i:Interaction.Triggers >
25 </ Button >
26 </ Grid >
27   </ UserControl >

界面xaml.cs:

View Code
1 using System;
2   using System.Collections.Generic;
3   using System.Linq;
4   using System.Net;
5   using System.Windows;
6   using System.Windows.Controls;
7 using System.Windows.Documents;
8 using System.Windows.Input;
9 using System.Windows.Media;
10 using System.Windows.Media.Animation;
11 using System.Windows.Shapes;
12
13 namespace AsycValidation
14 {
15 public partial class MainPage : UserControl
16 {
17 public MainPage()
18 {
19 InitializeComponent();
20
21 CompanyModel m1 = new CompanyModel() { CompanyID = 1 , CompanyName = " abc " };
22
23 companyViewModel = new CompanyViewModel(m1);
24 this .DataContext = companyViewModel;
25
26 }
27
28 public void button1_Click()
29 {
30 MessageBox.Show( " ok " );
31 }
32
33 public void button1_loaded()
34 {
35 MessageBox.Show( " loaded " );
36
37 }
38
39 public CompanyViewModel companyViewModel { get ; set ; }
40
41 }
42 }

注意给这个button定义了两个CallMethodAction的behavior:一个是点击事件,一个是加载Loaded事件。

1 < Button Content ="Button" Height ="36" HorizontalAlignment ="Left" Margin ="120,156,0,0" x:Name ="button1" VerticalAlignment ="Top" Width ="81" >
2 < i:Interaction.Triggers >
3 < i:EventTrigger EventName ="Click" >
4 < ei:CallMethodAction MethodName ="button1_Click" TargetObject =" {Binding ElementName=MyUserControl} " />
5 </ i:EventTrigger >
6 < i:EventTrigger >
7 < ei:CallMethodAction MethodName ="button1_loaded" TargetObject =" {Binding ElementName=MyUserControl} " />
8 </ i:EventTrigger >
9 </ i:Interaction.Triggers >
10 </ Button >

实现步骤:在VS2010中右键点击xaml文件“在Expression Blend中打开...”,然后左边拖一个Behavior到控件上来,配置属性,保存即可。要注意的是TargetObject属性配置。

Behavior or Command?

[Silverlight入门系列]使用MVVM模式(6):使用Behavior_第1张图片

MVVM设计模式为了实现UI元素也UI界面逻辑分离项目组决定使用MVVM设计模式。把界面逻辑写在ViewModel层,View层由美工设计,通过绑定VM层的数据,实现分离。可是问题出来了,UI元素如何触发VM层的事件呢? 最开始很多人建议使用command命令,因为silverlight/wpf的很多控件都提供了Command属性。感觉还挺好使,只需要绑定VM层的ICommand属性就可以了。可是后来问题越来越复杂,主要出来以下几方面的问题:

  (1) 只有ButtonBase提供了Command属性。其他没有继承这个基类的元素不提供此接口。需要自己扩展。

  (2) UI元素事件一般会有很多,比如左击、右击、拖拉、load、unload等。

  (3) UI元素可能在初始化时就会需要一些操作,比如Load事件。

 

开始我们使用Prism提供的DelegateCommandCompositeCommand类来处理,可是对于左、右击这种情况很棘手,重写ICommand,那么多UI元素想累死啊,终于在微软Expression blend中找到答案。使用behavior,一切搞定。

 

Behavior提供CallMethodAction、ChangePropertyAction、DataStateBehavior等十三个行为,足够你处理一般事件调用情况了。比如CallMethodAction:提供EventName、MethodName两个属性,EventName:你可以选择任意元素事件,MethodName:可以让你直接绑定方法,基本上可以解决所有问题。使用也很简单,只需要在Blend中把相关行为Behavior拖放到控件上,然后设置相关属性,一切OK!

有哪些Behavior可用?

首先在Expression Blend控件库左边的behavior部分已经有好多实现的行为,可直接拖过来用,当然网上资源也很多(如这个),还能自己扩展。

[Silverlight入门系列]使用MVVM模式(6):使用Behavior_第2张图片

自定义Behavior

举个例子,Silverlight文本框的一个老问题就是它只在失去焦点的时候才更新绑定源,失去焦点才做Validation,我们来编写一个behavior可以简单的解决这个问题:textbox文字改变就立即validation并更新绑定数据源。下载本CustomBehavior示例源代码

代码:

TextBoxUpdateBehavior : Behavior
1 using System;
2 using System.Net;
3 using System.Windows;
4 using System.Windows.Controls;
5 using System.Windows.Documents;
6 using System.Windows.Ink;
7 using System.Windows.Input;
8 using System.Windows.Media;
9 using System.Windows.Media.Animation;
10 using System.Windows.Shapes;
11 using System.Windows.Interactivity;
12
13 namespace AsycValidation
14 {
15 public class TextBoxUpdateBehavior : Behavior < TextBox >
16 {
17 public TextBoxUpdateBehavior()
18 {
19 }
20 protected override void OnAttached()
21 {
22 base .OnAttached();
23 AssociatedObject.TextChanged += AssociatedObjectOnTextChanged;
24 }
25 private void AssociatedObjectOnTextChanged( object sender, TextChangedEventArgs args)
26 {
27 var bindingExpr = AssociatedObject.GetBindingExpression(TextBox.TextProperty);
28 bindingExpr.UpdateSource();
29
30 }
31 protected override void OnDetaching()
32 {
33 base .OnDetaching();
34 AssociatedObject.TextChanged -= AssociatedObjectOnTextChanged;
35 }
36 }
37 }

xaml

Xaml code
< UserControl xmlns:wm ="clr-namespace:AsycValidation"
<TextBox Height
="30" HorizontalAlignment ="Left" Margin ="120,104,0,0" x:Name ="textBox2" Text =" {Binding CompanyID, Mode=TwoWay, NotifyOnValidationError=True} " VerticalAlignment ="Top" Width ="119" >
< i:Interaction.Behaviors >
< wm:TextBoxUpdateBehavior />
</ i:Interaction.Behaviors >
</ TextBox >
</ UserControl >

(运行后如何看效果:在第二个textbox输入1,输入2,输入1,看看validation)下载本CustomBehavior示例源代码

(本示例同时演示了Behavior, CustomBehavior, Validation, INotifyPropertyChanged, INotifyDataErrorInfo, MVVM, WCF Ria Service, 异步validation...)

你可能感兴趣的:(silverlight)