MVVM是一種模式,而WPF的數據綁定機制是一種WPF內建的功能集,二者是不相關的。html
可是,藉助WPF各類內建功能集,如數據綁定、命令、數據模板,咱們能夠高效的在WPF上實現MVVM。所以,咱們須要對各類MVVM相關的WPF內建功能集進行了解,才能在紮實的基礎上對MVVM進行學習與實踐。學習
本文是WPF學習03:Element Binding的後續,將說明實現數據綁定的三個重點:DataContext INotifyPropertyChanged IValueConverterthis
MVVM將User Interface切成了3個部分,View、Model、View Model.spa
三個部分區分以下:3d
View:界面代碼,並完成數據可視化。code
Model:一系列咱們與業務層交互的類。htm
View Model:1.將Model中須要顯示的部分,轉化爲對View友好的數據。 2.管理View與View之間的交互。 對象
依賴關係如上圖所示,V依賴於VM,反之不該該成立,VM依賴於M,反之亦不該成立。blog
在完成了對數據綁定、命令、數據模板的理解後,咱們再從新回來解釋MVVM。接口
在WPF學習03:Element Binding中,咱們只研究瞭如何在控件間實現數據綁定,在不指定ElementName時,Binding會在Source與RelativeSource也沒有設置的狀況下,一級一級的尋找DataContext,直到找到。
例子:
<StackPanel HorizontalAlignment="Center" TextBlock.Foreground="#019AFF" DataContext="{x:Static Colors.White}"> <!--指定Path,綁定對象的某個屬性--> <TextBlock Text="{Binding Path=R}"></TextBlock> <TextBlock Text="{Binding Path=G}"></TextBlock> <TextBlock Text="{Binding Path=B}"></TextBlock> <!--不指定Path,綁定整個對象--> <TextBlock Text="{Binding}"></TextBlock> </StackPanel>
比較經常使用的狀況下,咱們將DataContext設置在最頂層元素,通常狀況下爲Window。
咱們能夠在後臺代碼中配置DataContext:
public class Person { private Int32 _age; public Int32 Age { get { return _age; } set { _age = value; } } private String _name; public String Name { get { return _name; } set { _name = value; } } } private void Window_Loaded(object sender, RoutedEventArgs e) { person = new Person() { Name = "Kenny", Age = 30 }; this.DataContext = person; } private void Button_Click(object sender, RoutedEventArgs e) { person.Name = "John Locke"; person.Age = 40; }
XAML作的改動:
<StackPanel HorizontalAlignment="Center" TextBlock.Foreground="#019AFF"> <TextBlock Text="{Binding Path=Name}"></TextBlock> <TextBlock Text="{Binding Path=Age}"></TextBlock> <Button Click="Button_Click">Click me</Button> </StackPanel>
效果以下:
咱們能夠看到的確顯示了指望值,可是若是點擊按鍵的話,是看不到任何變化的,接下來即解釋緣由與解決方法。
WPF內建的數據綁定機制中,Dependency Property不需額外作任何配置,便可在通常狀況下創建數據綁定關係。WPF自建控件的各種屬性都是依賴屬性經傳統的.Net屬性包裝而成。
若是咱們但願將數據綁定的源設爲咱們本身定義的對象的屬性,且該屬性不爲依賴屬性,那麼就只有靠實現INotifyPropertyChanged接口,並在相應的屬性改變時調用PropertyChanged事件以通知目標元素。
咱們將以前的後臺代碼作以下的改動:
public class Person : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged;
private Int32 _age; public Int32 Age { get { return _age; } set { _age = value; if (PropertyChanged != null) PropertyChanged.Invoke(this,new PropertyChangedEventArgs("Age")); } } private String _name; public String Name { get { return _name; } set { _name = value; if (PropertyChanged != null) PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name")); } } }
效果以下:
某些特殊的時候,源屬性與目標屬性是沒法鏈接,須要進行轉換,這時,就須要用到ValueConverter.直接給個例子:
數據綁定實現根據年齡不一樣,文字顯示同顏色,效果:
XAML代碼:
<TextBlock Text="{Binding Path=Name}"></TextBlock> <TextBlock Name="AgeTextBlock" Text="{Binding Path=Age}"> <TextBlock.Foreground> <Binding Path="Age"> <Binding.Converter> <local:TextBlockColorValueConverter></local:TextBlockColorValueConverter> </Binding.Converter> </Binding> </TextBlock.Foreground> </TextBlock>
[ValueConversion(typeof(Boolean), typeof(Int32))] public class TextBlockColorValueConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if ((int)value < 18) return new SolidColorBrush(Colors.Violet); else return new SolidColorBrush(Colors.Red); } //這裏用不上數據從目標返回源,故返回null public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return null; } }
以前的數據綁定都是用XAML實現的,在此給出後臺代碼實現數據綁定的方法,實現剛纔的例子:
首先給兩個控件標個Name,並去掉以前的全部綁定相關代碼:
<TextBlock Name="NameTextBlock"></TextBlock> <TextBlock Name="AgeTextBlock"></TextBlock>
後臺代碼:
var bind = new Binding("Name") { Source = person, }; NameTextBlock.SetBinding(TextBlock.TextProperty, bind); bind = new Binding("Age") { Source = person, }; AgeTextBlock.SetBinding(TextBlock.TextProperty, bind); bind = new Binding("Age") { Source = person, Converter = new TextBlockColorValueConverter() }; AgeTextBlock.SetBinding(TextBlock.ForegroundProperty, bind);