Note7:MVVM模式之數據綁定
一、資源說明
(1)本文參考自:
- 一步步走進WPF的MVVM模式(二):數據綁定
- WPF之數據綁定總結
二、正文
數據綁定 (Data Binding)是WPF最重要的特性之一,也是實現 MVVM(WPF) 模式的一大支柱。 簡而言之,數據綁定就是將兩個屬性綁定在一起,源屬性(source)改變帶動目標屬性(target)一起改變。這樣也減少了事件(Events)的使用。 綁定源可以是任意對象的屬性,而目標必須是依賴對象的依賴屬性。 綁定源主要分為以下幾種場景(後面主要介紹前兩種):(1)依賴對象(DependencyObject):可以綁定到任意依賴對象的依賴屬性。
(2)CLR對象:可以綁定到任意CLR對象的公共屬性、子屬性以及索引器。綁定引擎使用CLR反射來獲取屬性值。
(3)動態對象:可以綁定到對象的可用屬性和索引器,該對象實現 IDynamicMetaObjectProvider 接口。
(4)ADO.NET對象:可以綁定到ADO.NET對象,如 DataTable 。ADO.NET DataView 實現 IBindingList 接口,該接口提供綁定引擎偵聽的更改通知。
(5)XML對象:可以綁定到並運行 XmlNode 、 XmlDocument 或 XmlElement 上的 XPath 查詢。
-
元素對元素的綁定
一種典型的場景是元素對元素的綁定(Element to Element binding),當一個元素屬性發生改變,界面上另外綁定的元素屬性也隨之改變。
<stackpanel> <textbox fontsize="{Binding ElementName=slider,Path=Value}" text="Welcome to WPF world." name="txt" /> <slider name="slider" maximum="26" minimum="14" /> <textblock text="{Binding ElementName=slider,Path=Value}" name="block" /> </stackpanel>
當我們拖動Slider的時候, TextBox
中字體的大小會隨之改變,下方 TextBlock
中也會更新值。數據綁定利用XAML中 binding
關鍵字,設置它的 ElementName
和 Path
屬性。也可以在代碼中設置:
Binding bind = new Binding
{
Source = this.slider,
Path = new PropertyPath("Value")
};
BindingOperations.SetBinding(this.txt, TextBox.FontSizeProperty, bind);
BindingOperations.SetBinding(this.block, TextBlock.TextProperty, bind);
這在自定義控件中用的比較多。
上面的例子中都遵循著"數據源到目標"的 數據流方向 ,叫做"OneWay"的形式。WPF支持以下幾種數據流方向:
(1)OneWay:綁定源更改時,更新綁定目標屬性。
(2)TwoWay:導致對源屬性或目標屬性的更改可自動更新對方。
(3)OneTime:當應用程序啟動或數據上下文更改時,更新綁定目標。比如用在命令(commands)上面。
(4)OneWayToSource:當目標屬性更改時更新源屬性。當目標屬性不是依賴屬性,而源屬性是依賴屬性的情況下,這就派上用場了。
(5)Default:使用綁定目標的默認Mode值。TextBox.Text屬性默認是TwoWay綁定,而大部分情況下,比如TextBlock.Text屬性就是OneWay綁定。
那麽何時觸發綁定呢?WPF為我們提供了 UpdateSourceTrigger
屬性,這是一個枚舉值: LostFocus
, PropertyChanged
, Explicit
, Default
。從字面意思也能知道何時觸發。需要註意的是,這個屬性只有當 Mode
被設置為 TwoWay
或者 OneWayToSource
的時候才能生效。
我們也可以手動觸發綁定:
var expr = BindingOperations.GetBindingExpression(this.txt, TextBox.FontSizeProperty);
expr.UpdateSource();
//or
expr.UpdateTarget();
-
綁定到CLR對象
這是最常用的一種情形了。
當程序初始化的時候,某個人的年齡數值為10。一旦我點擊了下面的Button,那麽上面的數值會立刻變成30:
這裏,我們沒有在Button的 Click
事件裏直接改變中間TextBlock控件的 Text
屬性,而是改變了這個 Person
對象的 Age
值,而最終的效果就是這個TextBlock控件的 Text
屬性也跟著改變了。Data Binding機制在中間起到橋梁的作用。下面,我們來看看 Person
類的實現細節:
public class Person:INotifyPropertyChanged { public Person(int _age) { age = _age; } private int age; public int Age { get { return age; } set { if (PropertyChanged != null) { //follow below order age = value; PropertyChanged(this, new PropertyChangedEventArgs("Age")); } } } public event PropertyChangedEventHandler PropertyChanged; }
這個Person類實現了 INotifyPropertyChanged
接口(命名空間:System.ComponentModel),這個接口是WPF中數據綁定的核心接口。換言之,如若要想讓CLR對象被成功綁定,那麽這個接口就是必須的。這個接口只包括一個事件 PropertyChanged
。
Person
類內部包含一個屬性 Age
,在其Setter中有一些邏輯,當然也是很容易懂的。如果這個屬性被改變了,那麽做一些更改,並向外部發出一些通知。
當然,你也可以將 Person
類繼承 DependencyObject
類,讓這個類變成依賴對象,裏面的屬性也就變成了依賴屬性。但是,不建議這樣做。
將需要被綁定的CLR對象實現 INotifyPropertyChanged
接口,這就是全部的準備工作了。
還有一種常見的情況:需要綁定一個集合對象,比如ListBox控件。這個時候,我們需要將這個集合對象繼承自 ObservableCollection<T>
類即可,在後面MVVM框架的內容中會對此有進一步的理解。
數據綁定的核心就是上面介紹的,但是綁定的過程中肯定會遇到一些細節問題,幸好WPF為我們提供了很多機制,可以參考這些介紹做一個了解:
- 數據模板(data template): http://wpftutorial.net/DataTemplates.html
- 值轉換器(value converters): http://wpftutorial.net/ValueConverters.html
- 綁定到多個屬性(bind to multiple properties): http://tech.pro/tutorial/809/wpf-tutorial-using-multibindings
- 驗證數據(validating data): http://wpftutorial.net/DataValidation.html
Note7:MVVM模式之數據綁定