首先簡單介紹下Binding以及其在WPF中的地位,僅接著會用一個小例子展現下Binding的魅力,並在後續的經驗中對Binding做更加深入詳細的分析。
工具/原料
Microsoft Expression Blend,Visual Studio 2010/2012/2013/2015
方法/步驟
對於簡單的介面佈局以及基礎的WPF學習,既可以使用Blend也可以使用VS,對於VS的版本沒有必要要求最新的,版本間的差異不會影響基礎的學習。
以後的程式碼我儘可能提供Blend和VS兩個版本,程式碼差異出我會標註出來,請注意觀察。
文章是從第六章開始寫的,我會盡快把前五章補齊,請耐心等待……
WPF產生背景
程式介面經過了CUI(Console User Interface)到GUI(Graphic User Interface)的發展歷程。
Windows GUI執行的機理是使用訊息(Message)來驅動程式向前執行,訊息的主要來源是使用者的操作,比如單擊滑鼠、按下按鈕,都會產生訊息,訊息會被Windows翻譯並送達到目標程式然後被程式所處理。這種訊息驅動機制迫使程式設計師把很多的精力放在了實現UI的程式設計上,這還不算完,隨著程式UI的日趨複雜,UI層面上的程式碼與用於處理資料的邏輯程式碼也漸漸糾纏在一起變得難以維護。為了避免這樣的問題,程式設計師們總結出了MVC(Model View Controler)和MVP(Model View Presenter)等諸多設計模式來把UI相關的程式碼與資料邏輯相關的程式碼分開。
為解決上面的問題WPF採用資料驅動UI的設計理念,將UI程式碼與資料邏輯
程式碼進行分離。WPF作為一種專門的展示技術,華麗的外觀和動畫只是它的表層現象,更重要的是它在深層次上幫助程式設計師把思維的重心固定在了邏輯層,讓展示層永遠處於邏輯層的從屬低位。WPF具有這種能力的關鍵是它引入了Data Binding概念以及與之配套的依賴屬性(Dependency Property)系統和DataTemplate。
Data Binding在WPF中的地位
Data Binding在WPF系統中起到的是資料高速公路的作用,有了這條高速公路,加工好的資料會自動送達使用者介面加以顯示,被使用者修改過的資料也會自動傳回到邏輯層,一旦資料被加工好後又會送達到使用者介面……程式的邏輯層就像一個強有力的引擎不停的運轉,用加工好的資料驅動程式的使用者介面以文字、圖形、動畫等形式把資料顯示出來——這就是“資料驅動UI”。
Binding模型圖
Binding簡單例項演示
一般情況下,Binding源是邏輯層的物件,Binding目標是UI層的控制元件物件。
通過Blend或VS建立一個WPF專案(因為後面牽扯到程式碼的修改建議用VS,VS中的智慧提示做的比Blend要好),然後新增一個Student的類,如下:
Student類程式碼如下:
class Student
{
private string name;
public string Name
{
get{return name;}
set{name=value;}
}
}
改造Student類
在進行繫結時要確認繫結的源,繫結源的屬性(即繫結的路徑Path)以及繫結的目標物件的屬性。本例簡單Binding的源即Student物件,Binding源的屬性即Student物件的Name屬性,目標物件的屬性一會進行設定。
到目前為止光有屬性還不行,Binding是一種自動機制,當值變化後屬性要有能力通知Binding,讓Binding把變化傳遞給UI元素。可以通過設定屬性的set語句激發一個PropertyChanged事件,這個事件不用我們自己宣告,我們要做的是讓資料來源的類實現System.ComponetModel名稱空間中的INotifyPropertyChanged介面,當為Binding設定了資料來源後,Binding就會自動偵聽來自這個介面的PropertyChanged事件。程式碼如下:
class Student : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PorpertyChanged;
private string name;
public string Name
{
get{return name;}
set
{
name=value;
if (this.PorpertyChanged!=null)
{
this.PorpertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));
}
}
}
}
設定主窗體
在主窗體上新增TextBox和Button,其中TextBox為Binding的目標物件。主窗體的XAML程式碼如下:
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x=";
Title="MainWindow" Height="110" Width="300">
顯示效果如下圖:
使用Binding連線資料來源和目標UI
public partial class MainWindow : Window
{
Student stu;
public MainWindow()
{
InitializeComponent();
//準備資料來源
stu = new Student();
//準備Binding
Binding bd = new Binding();
bd.Source = stu;
bd.Path = new PropertyPath("Name");
//使用Binding連線資料來源和目標
BindingOperations.SetBinding(this.txtName, TextBox.TextProperty, bd);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
stu.Name += "Name";
}
}
點選按鈕效果如下圖:
BindingOperations.SetBinding方法的三個引數
(1)指定Binding的目標,本例中為this.txtName
(2)用於為Binding指明把資料送達到目標的哪個屬性。只是你會發現這裡用的不是物件的屬性而是類的一個靜態只讀的DependencyProperty型別成員變數!這類屬性的值可以通過Binding依賴在其他物件的屬性值上,被其他物件的屬性值所驅動
(3)指定使用哪個Binding例項將資料來源和目標關聯起來
Binding的進一步簡化
因為TextBox這類UI元素的基類FrameworkElement對BindingOperations.SetBinding(...)方法進行了封裝,其封裝的結果也叫SetBinding,只是引數列表發生了變化。封裝程式碼如下:
public BindingExpressionBase SetBinding(DependencyProperty dp, BindingBase binding)
{
return BindingOperations.SetBinding(this,dp,binding);
}
基於上面的封裝對Binding的程式碼可進行如下的簡化:
public MainWindow()
{
InitializeComponent();
this.SetBinding(TextBox.TextProperty, new Binding("Name") { Source=stu});
}