1.元素綁定
元素綁定是數據綁定的一種,將源對象和目標對象的元素綁定在一起,使從源對象提取一些信息來設置目標對象的屬性。
元素綁定的好處是使得元素的交互方式自動化,當用戶修改控件時,另一元素自動更新,不需要編寫樣板代碼(這是WinForm技術不能實現的)。
2.綁定表達式
該窗口中包含兩個控件:一個Slider控件和一個單行文本TextBlock控件。通過拖動條形控件的滑塊調整文本字體大小。
顯然不用元素綁定也容易實現,可以簡單地響應Slider.ValueChanged事件,將滑塊的當前值複製到TextBlock來實現。但是使用元素綁定實現起來會更簡單。
<Slider Name="slider" Minimum="1" Maximum="40" Value="10" TickFrequency="1" TickPlacement="TopLeft" Margin="3"></Slider>
<TextBlock Name="textblock" Text="Simple Text" FontSize="{Binding ElementName=slider, Path=Value}" Margin="3"></TextBlock>
綁定表達式以單詞Binding開頭,ElementName指示源元素,Path指示源元素的屬性。之所以用Path而不用Property是因爲Path可能指向一個屬性的屬性(如FontFamily.Source)、屬性索引器(如Content.Children[0])或更多層的屬性的屬性的屬性等。
如果在上面代碼基礎上再加兩個按鈕,用於設置最小字體和最大字體。
單擊Set to Large按鈕,會運行下面代碼:
private void Button_Click_SetLarge(object sender, RoutedEventArgs e)
{
slider.Value = slider.Maxmum;
}
實際效果是滑塊滑到最大值,文本字體大小變爲對應的最大值。
然而如果我們把代碼寫成下面的形式則不能正常工作。
private void Button_Click_SetLarge(object sender, RoutedEventArgs e)
{
textblock.FontSize = slider.Maxmum;
}
上面代碼中修改了文本的大小,但是滑塊沒有更新。而且再調整滑塊時文本大小不會跟着變化。上面代碼破壞了元素綁定。
3.綁定模式
可以通過綁定模式來解決上述問題。代碼如下:
<TextBlock Name="textblock" Text="Simple Text" FontSize="{Binding ElementName=slider, Path=Value, Mode=TwoWay}" Margin="3"></TextBlock>
Binding的Mode屬性爲枚舉類型BindingMode。具體的值有:
OneWay:單向綁定。
TwoWay:雙向綁定。
OneTime:一次綁定。只在程序運行時更新目標值。
OneWayToSource:反向單向綁定。
Default:缺省值。默認是單向綁定。
4.使用代碼創建綁定
也可以使用C#代碼來創建綁定:
Binding binding = new Binding();
binding.Source = slider;
binding.Path = new PropertyPath("Value");
binding.Mode = BindingMode.TwoWay;
textblock.SetBinding(TextBlock.FontSizeProperty, binding);
使用下面代碼移除綁定:
BindingOperations.ClearBinding(textblock, TextBlock.FontSizeProperty);
或
BindingOperations.ClearAllBindings(textblock);
5.更新時機問題
從目標到源的更新可能不會立即發生。主要出現在TwoWay和OneWayToSource模式下。例如,用一個文本輸入框TextBox和Slider的Value綁定,通過在TextBox裏輸入數字來動態修改Slider的Value。如果使用TwoWay模式,則輸入數字後Slider.Value不會自動更新,只有當TextBox失去焦點時才更新。
<TextBox Name="textbox" Height="23" TextWrapping="Wrap" Text="{Binding ElementName=slider, Path=Value, Mode=TwoWay}" Width="120"/>
如果不想出現這種情況,想要在TextBox輸入任意值時就更新Slider,則有兩種方法可以解決:
1.在上面代碼里加入UpdateSourceTrigger=PropertyChanged使得只要輸入內容改變就更新而不是失去焦點才更新;
2.讓Slider去綁定TextBox,Mode還是TwoWay。
6.綁定到非元素對象
之前我們用到的是Binding.ElementName元素對象,它必須是XAML文件裏的元素。然而我們也可以綁定其他非元素對象,例如綁定系統的靜態數據對象、綁定資源等。
當綁定非元素對象時,需用到下面三種之一來替代ElementName:
(1)Source:通常是一個已存在的靜態對象。例如綁定Net類庫的靜態變量代碼如下:
<TextBlock Name="textblock" Text="{Binding Source={x:Static SystemFonts.IconFontFamily}, Path=Source}" Margin="3"></TextBlock>
綁定程序靜態資源的代碼如下:
<Window.Resources>
<FontFamily x:Key="CustomFont">Calibri1</FontFamily>
</Window.Resources>
<TextBlock Name="textblock2" Text="{Binding Source={StaticResource CustomFont}, Path=Source}" Margin="3"></TextBlock>
(2)RelativeSource:從上下文找到符合綁定要求的元素進行綁定。包括在當前元素的所有屬性進行搜索,和在其父節點、祖父節點一直往上的上下文搜索。
例如:綁定當前控件自己的Margin的值,如下:
<TextBlock Name="textblock3" Margin="4,4,4,4" Text="{Binding RelativeSource={RelativeSource Self},Path=Margin}"></TextBlock>
例如:綁定當前控件祖先節點Window窗口的名字,如下:
<TextBlock Name="textblock3" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}},Path=Title}"></TextBlock>
(3)DataContext:如果有大量元素綁定同一對象,代碼標記會有很長的重複。使用DataContext綁定源可以簡化代碼。例如下面的代碼就很臃腫:
<StackPanel>
<TextBlock Text="{Binding Source={x:Static SystemFonts.IconFontFamily},Path=Source}">
</TextBlock>
<TextBlock Text="{Binding Source={x:Static SystemFonts.IconFontFamily},Path=LineSpacing}"> </TextBlock>
<TextBlock Text="{Binding Source={x:Static SystemFonts.IconFontFamily}, Path=FamilyTypefaces[0].Style}"> </TextBlock>
</StackPanel>
代碼中所有TextBlock綁定相同的數據SystemFonts.IconFontFamily,但是它們綁定的屬性不同。我們使用DataContext對代碼進行簡化如下:
<StackPanel DataContext="{x:Static SystemFonts.IconFontFamily}">
<TextBlock Text="{Binding Path=Source}">
</TextBlock>
<TextBlock Text="{Binding Path=LineSpacing}"> </TextBlock>
<TextBlock Text="{Binding Path=FamilyTypefaces[0].Style}"> </TextBlock>
</StackPanel>