System.Windows.Data.Binding 類別是 WPF 資料繫結的核心,它在「目標」(必須為 DependencyProperty)與「來源」(任意 CLR 物件、XML 節點、另一個 UI 元素)之間建立雙向或單向同步通道。一旦建立,繫結引擎自動處理變更通知、型別轉換、驗證、格式化,開發者無需手寫同步程式碼。
<TextBox x:Name="src" Text="來源文字"/>
<TextBlock Text="{Binding ElementName=src, Path=Text}"/>
<TextBlock Text="{Binding ElementName=src, Path=ActualWidth, StringFormat='寬度: {0}px'}"/>
C# 等價程式碼:
var b = new Binding { Source = src, Path = new PropertyPath("Text") };
target.SetBinding(TextBlock.TextProperty, b);
// 移除繫結:BindingOperations.ClearBinding(target, TextBlock.TextProperty);
// 或直接指派新值:target.Text = "固定值";
關鍵屬性:ElementName/Source/RelativeSource 三選一指定來源;Path 指定屬性路徑;Mode(OneWay/TwoWay/OneTime/OneWayToSource/Default);UpdateSourceTrigger(PropertyChanged/LostFocus/Explicit/Default)。
任何 IEnumerable 皆可作為 ItemsSource,但需 集合變更通知 才能讓 UI 自動增刪項目。標準做法:集合類別繼承 ObservableCollection<T>(已實作 INotifyCollectionChanged + INotifyPropertyChanged)。
public class Photos : ObservableCollection<Photo> { }
<ListBox x:Name="lb" ItemsSource="{Binding Source={StaticResource photos}}" DisplayMemberPath="Name"/>
DisplayMemberPath 指定顯示屬性;複雜呈現改用 ItemTemplate(見資料模板章節)。
<StackPanel DataContext="{StaticResource myEmployee}">
<TextBox Text="{Binding Path=FirstName}"/>
<TextBox Text="{Binding Path=LastName}"/>
<TextBox Text="{Binding Path=Title}"/>
</StackPanel>
子元素未指定 Source 時,向上邏輯樹尋找最近非空 DataContext。RelativeSource={RelativeSource AncestorType=Window} 可跨層級存取。
適用於 ContentControl.ContentTemplate、ItemsControl.ItemTemplate、HeaderedContentControl.HeaderTemplate。模板內共享父繫結上下文:
<ListBox ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Gray" BorderThickness="1" Margin="2" Padding="4">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ThumbnailPath}" Width="48" Height="48"/>
<StackPanel Margin="8,0">
<TextBlock Text="{Binding Name}" FontWeight="Bold"/>
<TextBlock Text="{Binding Date, StringFormat='yyyy-MM-dd'}" Foreground="Gray"/>
</StackPanel>
</StackPanel>
<ToolTipService.ToolTip>
<TextBlock Text="{Binding Description}"/>
</ToolTipService.ToolTip>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
模板可提升為資源字典 (ResourceDictionary) 跨視窗/專案共用。
實作 IValueConverter 介面,Convert(目標←源)、ConvertBack(目標→源)。註冊為資源後掛載於 Binding.Converter。
public class CountToTextConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
int n = (int)value; return $"{n} {(n == 1 ? "項目" : "項目")}";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
=> throw new NotSupportedException();
}
<Window.Resources>
<local:CountToTextConverter x:Key="countConv"/>
</Window.Resources>
<TextBlock Text="{Binding Count, Converter={StaticResource countConv}}"/>
常見應用:BoolToVisibilityConverter、NullToVisibilityConverter、EnumToDescriptionConverter、ByteArrayToImageConverter 等。
Binding.ValidationRules 集合接受繼承 ValidationRule 的類別。驗證發生於 Converter 之前,失敗即阻斷源更新並設定 Validation.HasError=True。
public class JpgFileRule : ValidationRule {
public override ValidationResult Validate(object value, CultureInfo culture) {
var path = (value ?? "").ToString();
if (!File.Exists(path)) return new ValidationResult(false, "檔案不存在");
if (!path.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase)) return new ValidationResult(false, "僅限 JPG 檔案");
return ValidationResult.ValidResult;
}
}
XAML 掛載並搭配即時觸發與錯誤模板(見前文章節)。
ObjectDataProvider:在 XAML 實例化任意類別並呼叫方法/屬性作為繫結源,支援 MethodParameters、ObjectInstance、ObjectType。XmlDataProvider:載入 XML 文件(Source URI 或 Document 內嵌),搭配 XPath 查詢節點集合。<ObjectDataProvider x:Key="employees" ObjectType="{x:Type local:EmployeeService}" MethodName="GetAll"/>
<ListBox ItemsSource="{Binding Source={StaticResource employees}}"/>
PresentationTraceSources 提升等級:<Binding diag:PresentationTraceSources.TraceLevel=High>。Path=Order.Customer.Address.City 任一節點為 null 即中斷;ViewModel 暴露扁平屬性更穩健。VirtualizingStackPanel.IsVirtualizing="True" + ItemsPanel 設定 VirtualizingStackPanel。Brush、Transform 等標記 x:Shared="False" 或程式碼 Freeze() 跨執行緒共用。