詳解WP開發(fā)中MVVM模式的綁定功能
MVVM這個模式在WPF和Silverlight開發(fā)中已經(jīng)非常流行了,因為WP7的應(yīng)用開發(fā)也是Silverlight的,MVVM的一樣可以適用。雖然MVVM有不少明確的定義,但是我也沒有找到比較統(tǒng)一的來描述它,所以大概說一下我的總結(jié):
MVVM和MVC、MVP一樣都是為了分離呈現(xiàn)和業(yè)務(wù)為目標(biāo)的設(shè)計模式,MVVM使用了WPF系列庫特有的綁定機(jī)制從視圖層移除絕大部分的業(yè)務(wù)處理和業(yè)務(wù)數(shù)據(jù)提供的邏輯。于獨立的視圖模型層更有利于測試。
大概結(jié)構(gòu)如下:

View更關(guān)注界面的呈現(xiàn),ViewModel更關(guān)注業(yè)務(wù)處理,Model作為之間交互的模型數(shù)據(jù)。
MVVM的綁定Binding
WPF和Silverlight提供了強(qiáng)大的綁定功能,為MVVM提供了必要的基礎(chǔ):
1.數(shù)據(jù)來源
在使用綁定之前,需要有基礎(chǔ)的數(shù)據(jù)的來源,如CLR對象和XML形式,在MVVM里就應(yīng)該這個View視圖對于的ViewModel視圖模型。將ViewModel對象設(shè)定到視圖根元素的FrameworkElement. DataContext屬性上完成數(shù)據(jù)來源的設(shè)置,根元素一般就是phone:PhoneApplicationPage。
代碼很簡單:
- public partial class MainPageView
 - {
 - // 構(gòu)造函數(shù)
 - public MainPageView()
 - {
 - InitializeComponent();
 - DataContext = new MainPageViewModel();
 - }
 - }
 
2.數(shù)據(jù)綁定
數(shù)據(jù)綁定是在應(yīng)用程序 UI 與業(yè)務(wù)邏輯之間建立連接的過程。如果綁定具有正確設(shè)置并且數(shù)據(jù)提供正確通知,則當(dāng)數(shù)據(jù)更改其值時,綁定到數(shù)據(jù)的元素會自動反映更改。

在MVVM里,簡單的說就是能夠讓視圖View和視圖模型ViewModel的數(shù)據(jù)能夠動態(tài)同步更新,并且支持更新的方法。實現(xiàn)同步更新需要讓ViewModel實現(xiàn)INotifyPropertyChanged接口。
- public interface INotifyPropertyChanged
 - {
 - //在更改屬性值時發(fā)生。
 - event PropertyChangedEventHandler PropertyChanged;
 - }
 - PropertyChangedEventArgs的定義如下:
 - public class PropertyChangedEventArgs : EventArgs
 - {
 - // propertyName: 已更改的屬性的名稱。
 - public PropertyChangedEventArgs(string propertyName);
 - public string PropertyName { get; }
 - }
 
只需要在ViewModel的屬性更新時觸發(fā)PropertyChanged并傳入更改的屬性名稱就可以了。
完整示例:
- public class DemoCustomer : INotifyPropertyChanged
 - {
 - public event PropertyChangedEventHandler PropertyChanged;
 - private void NotifyPropertyChanged(String info)
 - {
 - if (PropertyChanged != null)
 - {
 - PropertyChanged(this, new PropertyChangedEventArgs(info));
 - }
 - }
 - public string CustomerName
 - {
 - get
 - {
 - return this.customerNameValue;
 - }
 - set
 - {
 - if (value != this.customerNameValue)
 - {
 - this.customerNameValue = value;
 - NotifyPropertyChanged("CustomerName");
 - }
 - }
 - }
 - }
 
在XAML里面添加下面的代碼就可以實現(xiàn)數(shù)據(jù)綁定。
- <TextBox Text="{Binding Path=CustomerName, Mode=TwoWay}" />
 
這樣在界面修改TextBox 或 后臺程序修改CustomerName的時候都可以同步更新(內(nèi)部還解決線程切換的問題)數(shù)據(jù)綁定可以方便的同步View和ViewModel,并很好的減少了耦合。
3.命令綁定
命令是WPF中的輸入機(jī)制,它提供的輸入處理比設(shè)備輸入具有更高的語義級別。例如,在許多應(yīng)用程序中都能找到的“復(fù)制”、 “剪切”和 “粘貼”操作就是命令。
命令支持自定義命令,實現(xiàn)自定義命令需要實現(xiàn)ICommand接口。
- public interface ICommand
 - {
 - // 當(dāng)出現(xiàn)影響是否應(yīng)執(zhí)行該命令的更改時發(fā)生。
 - event EventHandler CanExecuteChanged;
 - // 定義用于確定此命令是否可以在其當(dāng)前狀態(tài)下執(zhí)行的方法。
 - bool CanExecute(object parameter);
 - // 定義在調(diào)用此命令時調(diào)用的方法。
 - void Execute(object parameter);
 - }
 
自定義命令是MVVM命令綁定的基礎(chǔ)。實現(xiàn)一個最簡單的自定義Command,暫時無視CanExecuteChanged變更和傳入?yún)?shù)。
- public class InvokeCommand : ICommand
 - {
 - private readonly Action action;
 - public event EventHandler CanExecuteChanged;
 - public InvokeCommand(Action action)
 - {
 - this.action = action;
 - }
 - public bool CanExecute(object parameter)
 - {
 - return true;
 - }
 - public void Execute(object parameter)
 - {
 - action();
 - }
 - }
 
在ViewModel里面添加屬性:
- public ICommand HelloCommand{ get; set; }
 
ViewModel構(gòu)造函數(shù)內(nèi)添加:
- HelloCommand = new InvokeCommand(() => MessageBox.Show(“Hello world”));
 
在ButtonBase類里面有一個 Command屬性,獲取或設(shè)置當(dāng)按此按鈕時要調(diào)用的命令。
- <button command="{Binding HelloCommand}" />
 
這樣點擊button就會觸發(fā)MessageBox.Show(“Hello world”)); 命令綁定提供了簡單的機(jī)制,讓業(yè)務(wù)處理的消息可以在ViewModel里執(zhí)行。
4.擴(kuò)展命令綁定為動作綁定(事件綁定)
命令綁定僅僅提供了ButtonBase的點擊事件,要是有更復(fù)雜的事件需要使用到動作綁定,這個基礎(chǔ)是由System.Windows.Interactivity提供的,在C:\Program Files (x86)\Microsoft SDKs\Expression\Blend\Windows Phone\v7.1\Libraries里面可以找到。
另外動作綁定并沒有正式的名稱,我只是為了統(tǒng)一隨口叫的。動作綁定就稍微復(fù)雜一點,首先我們需要實現(xiàn)一個自定義的動作,繼承TriggerAction實現(xiàn)自己的InvokeAction。
- public class InvokeAction:TriggerAction<FrameworkElement>
 - {
 - public static readonly DependencyProperty CommandProperty
 - = DependencyProperty.Register("Command", typeof (ICommand), typeof (InvokeAction));
 - public ICommand Command
 - {
 - get { return (ICommand) GetValue(CommandProperty); }
 - set { SetCurrentValue(CommandProperty, value); }
 - }
 - protected override void Invoke(object parameter)
 - {
 - ICommand command = Command;
 - if (command == null)return;
 - if (!command.CanExecute(parameter)) return;
 - command.Execute(parameter);
 - }
 - }
 
里面定義了一個Command的依賴屬性,用法和ButtonBase一樣,這樣就可以方便綁定命令了。
XAML代碼如下:
首先引用System.Windows.Interactivity添加命名空間:xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
- <Button Content="Button">
 - <i:Interaction.Triggers>
 - <i:EventTrigger EventName="Click">
 - <local:InvokeAction Command="{Binding HelloCommand}" />
 - </i:EventTrigger>
 - </i:Interaction.Triggers>
 - </Button>
 
i:EventTrigger的EventName可以設(shè)置該控件上的各種事件,這里為了方便還是用的點擊Clicklocal:InvokeAction將自定義動作InvokeAction元素添加進(jìn)去,還是繼續(xù)使用上一節(jié)定義的HelloCommand,同樣點擊Button 之后Hello World就顯示出來了。當(dāng)然使用i:InvokeCommandAction 更方便,我只是演示一下。
原文鏈接:http://www.cnblogs.com/kiminozo/archive/2012/01/27/2330112.html















 
 
 

 
 
 
 