WPF 資料綁定將 UI 與資料模型解耦。本文透過「姓名/暱稱管理」範例,深度解析 **實體類通知**、**集合變更通知**、**綁定語法**、**ItemTemplate 數據模板** 四大核心支柱。
public class Nickname : INotifyPropertyChanged {
private string name, nick;
public string Name { get => name; set { name = value; OnPropertyChanged("Name"); } }
public string Nick { get => nick; set { nick = value; OnPropertyChanged("Nick"); } }
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string prop) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}
作用:屬性值變更時發送通知,UI 自動更新綁定目標。**適用於單一物件屬性變更**。
public class Nicknames : ObservableCollection<Nickname> { }
// 繼承即擁有 Add/Remove/Clear 等操作的 CollectionChanged 事件自動觸發
作用:集合增刪項目時發送通知,UI 自動增減 ListBox 項目。**適用於集合結構變更 (Add/Remove/Replace)**。
| 介面 | 通知觸發時機 | 典型場景 |
|---|---|---|
INotifyPropertyChanged | 單一物件屬性值改變 | TextBox 雙向綁定、屬性面板刷新 |
ObservableCollection<T> | 集合增/刪/移動/清空 | ListBox/DataGrid 項目增減、動態篩選 |
public partial class Window1 : Window {
private Nicknames names; // 內部集合引用
public Window1() {
InitializeComponent();
this.addButton.Click += addButton_Click;
this.names = new Nicknames(); // 實例化
// 關鍵:將集合設為 DockPanel 的 DataContext
this.dockPanel.DataContext = this.names;
}
void addButton_Click(...) {
names.Add(new Nickname { Name = "New", Nick = "Entry" }); // 觸發 CollectionChanged
}
}
<DockPanel x:Name="dockPanel">
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<TextBlock VerticalAlignment="Center">Name: </TextBlock>
<TextBox Text="{Binding Path=Name}" /> <!-- 綁定當前項目 Name -->
<TextBlock VerticalAlignment="Center">Nick: </TextBlock>
<TextBox Text="{Binding Path=Nick}" />
</StackPanel>
<Button DockPanel.Dock="Bottom" x:Name="addButton">Add</Button>
<ListBox
ItemsSource="{Binding}" <!-- 綁定集合本身 (DataContext) -->
IsSynchronizedWithCurrentItem="True" /> <!-- 同步選中項為 CurrentItem -->
</DockPanel>
無模板時 ListBox 呼叫 `ToString()` 顯示類型名。需定義 `
<ListBox ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock Text="{Binding Path=Name}" />:
<TextBlock Text="{Binding Path=Nick}" />
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
DataTemplate 的 `DataContext` 自動設為**集合中的單個項目** (Nickname 實例)。<!-- 標記擴展語法 -->
<TextBox Text="{Binding Path=Name}" />
<!-- 等價物件元素語法 -->
<TextBox>
<TextBox.Text>
<Binding Path="Name" />
</TextBox.Text>
</TextBox>
<!-- 等價後台代碼 -->
Binding b = new Binding { Path = "Name" };
textBox1.SetBinding(TextBox.TextProperty, b);
範例中 ListBox 初始 3 行資料來源在原書 1.8 節透過 **資源系統** 定義 (見前文「資源與映射」),此處略過。
這四大支柱構成了 WPF MVVM 模式的資料層基石。