1. 程式人生 > 程式設計 >WPF實現資料繫結

WPF實現資料繫結

簡單而言,資料繫結是一種關係,這種關係告訴WPF 從一個源目標物件中提取一些資訊,並且使用該資訊設定為目標物件的屬性。目標屬性總是依賴項屬性,並且通常位於WPF元素中。

然而,源物件可以是任何內容,可是是隨機生成的一個物件、也可以是的資料物件,或者手動建立的物件。

簡單繫結

為了能夠簡單理解這種繫結關係,接下來簡單示例,用一個數值滾動條,動態修改一個文字的字型大小,通過繫結的方式。

<StackPanel>
    <Slider Name="s1" Value="10" Maximum="100"></Slider>
 
    <TextBlock FontSize="{Binding ElementName=s1,Path=Value}" Text="看著我" ></TextBlock>
</StackPanel>

上圖中,TextBlock的字型大小FontSize通過繫結的形式與名稱為s1的元素的Value屬性繫結。

注:資料繫結表示式使用了XAML標記擴充套件,所以繫結表示式以單詞Binding 開頭。該示例中設定的兩個屬性: ElementName(源物件元素) 和Path(源物件元素中的屬性)。

執行測試效果:

WPF實現資料繫結

繫結錯誤

WPF不會引發異常來通知與資料繫結相關的問題,如果指定的元素不存在或錯誤,不會收到任何提示,最簡單的只是目標的屬性無法發生改變,不過,WPF仍然會在輸出視窗顯示其繫結失敗的具體細節。

繫結模式

在上面的示例中,只是一個最簡單的繫結,我們可以假設一個環境,在上面的例子基礎上另外加一個按鈕,去單獨實現字型的大小設定,然而拖動條並不會隨著按鈕設定的字型大小而改動。

但是在實際應用中,我們甚至會用到的多種繫結模式,所以在WPF中,含有5種繫結的模式,包含在System.Windows.Data.BindingMode列舉中。

OneWay當源屬性變化時更新目標屬性
TwoWay當源資料變化時更新目標屬性,並且當目標屬性變化時更新源屬性
OneTime最初根據源屬性值設定目標屬性。然而,在此之後的所有改變都會被忽略(除非繫結被設定為一個完全不同的物件或者呼叫BindingExpression.UpdateTarget()方法,如稍後所介紹的那樣)。通常,如果知道源屬性不會變化,可以使用這種模式降低開銷。
OneWayToSource和OneWay 類似,但是方向相反。當目標屬性變化時更新源屬性(這看起來有點像向後傳遞),http://www.cppcns.com
但目標屬性永遠不會更新。
Default此類繫結依賴於目標屬性。它既可以是雙向的(對於使用者設定的屬性,如Textbox.Text屬性),也可以是單向的(對於所有其他屬性)。除非明確指定了另外一種模式,否則所有繫結都使用該方法。

在此,對於OneTime設定過一次就無效,和預設default模式就不過多介紹,下面對其他集中進行簡單分析:

WPF實現資料繫結

利用程式碼進行資料繫結

下面程式碼演示如何將上面的示例進行繫結:

private void Window_Loaded(object sender,RoutedEventArgs e)
 {
     Binding bind = new Binding();
     bind.Source = s1; //指定源物件
     bind.Mode = BindingMode.Default; //設定繫結模式
     bind.Path = new PropertyPath("Value");  //關聯繫結的屬性
     txtfont.SetBinding(TextBlock.FontSizeProperty,bind);  //繫結物件
 }

下面程式碼演示如何解除資料繫結:

private void Window_Loaded(object sender,RoutedEventArgs e)
  {
      //刪除指定目標物件的  指定屬性資料繫結
      BindingOperations.ClearBinding(txtfont,TextBlock.FontSizeProperty);
 
      //刪除指定目標物件的所有資料繫結
      BindingOperations.ClearAllBindings(txtfont);
  }

注意:以上的兩個移除資料繫結的方法,可以刪除任何形式的繫結,無論是程式碼建立的繫結還是通過XAML標記的繫結。

繫結更新:

在上面的示例中,從 源物件 -> 目標物件,源物件的值發生改變,目標會立刻響應。但是從目標 > 源,未必會立即發生。

在WPF中,他們的行為右 binding中的UpdateSourceTrigger屬性控制,關於UpdateSourceTrigger 下面列出了對應的列舉值

propertyChanged當目標屬性發生變化時立即更新源目標
LostFocus當目標屬性發生變化時並且目標丟失焦點是更新源目標
Explicit除非呼叫BindingExpression.UpdateSource()方法,否則無法更新資源
Default根據目標屬性的元資料確定更新行為,大多數屬性的預設行為是PropertyChanged,但是TextBox.Text的屬性預設行為是LoastFocus

示例,對於TextBox控制元件,新增UpdateSourceTrigger=PropertyChanged 以達到更新源目標,但是往往在實際應用中,TextBox會頻繁的變化,從而導致多次更新源目標,&rfjunnbsp;

PropertyChenged更新反而會是應用程式執行更加緩慢,要完全控制源物件的更新時機,可以選擇 Explicit模式,例如,新增一個按鈕,在按鈕中呼叫UpdateSource方法已達到

更新的目的。

<TextBlock Grid.Row="1" Text="看著我" Name="txtfont"></TextBlock>
<TextBox Grid.Row="2" Margin="10" Text="{Binding ElementName=txtfont,Path=FontSize,UpdateSourceTrigger=PropertyChanged}"></TextBox>

注:在呼叫UpdateSource之前,需要通過GetBindingExpression()方法獲取到BindingExpression物件,從而呼叫UpdateSource()方法。

private void Button_Click(object sender,RoutedEventArgs e)
   {
       BindingExprhttp://www.cppcns.comession exp = txtfont.GetBindingExpression(TextBlock.FontSizeProperty);
       exp.UpdateSource();
   }

非元素繫結:

在上面的例子中,一直圍繞著元素之間的繫結,以及一些繫結的模式的介紹,但是在我們的實際應用當中,更多的是於資料打交道,就像常見的Grid表格,需要繫結對應資料庫表的每個欄位。

當繫結一個非元素物件時候,這個時候就不能使用 ElementName屬性,在WPF中,提供了多種屬性以在實際應用中選擇:

Source提供資料的物件本身
RelativeSource使用RelativeSource物件指向源目標,
DataContext從當前元素向下,找到第一個非空的DataContext屬性。

Source屬性:

如下,我們定義了一個Custom的資源物件,同時建立了一個TextBlock物件用Source進行了物件繫結,此時,TextBlock顯示的Text則為Tom

<Window.Resources>
        <FontFamily x:Key="Custom">Tom</FontFamily>
    </Window.Resources>
 
    <StackPanel>
        <TextBlock Text="{Binding Source={StaticResource Custom},Path=Source}" Height="30"/>
    </StackPanel>

RelativeSource屬性:

如下,定義了一個RelativeSource物件,Mdoe選擇了FindAncestor(該模式通知元素直到發現AncestorType定義的元素型別,如下型別為 window),選擇的Paht為title屬性

<StackPanel>
        <TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}},Path=Title}" Height="30"/>
    </StackPanel>

DataContext屬性:

TextBlock綁定了DataContext屬性,WPF會在元素樹種,找到第一個不為null的資料上下文,此時後臺需要對DataContext進行繫結指定的上下文物件。

<TextBlock Text="{Binding Width}"/>

該示例種,綁定了自身為上下文物件,所有TextBlock找到的第一個Width屬性為windows窗體本身的Width屬性

private void Window_Loaded(object sender,RoutedEventArgs e)
   {
       this.DataContext = this;
   }

到此這篇關於WPF實現資料繫結的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支援我們。