初始版本僅在視窗放置兩個 TextBox、一個 Button,程式碼手動將 Person 物件屬性指派給控制項(範例 4-1、4-2、4-3)。點擊 Birthday 按鈕增加年齡,但 UI 不會自動更新(圖 4-2)。
在 Click 事件中加入 ageTextBox.Text = person.Age.ToString()(範例 4-4)。雖然單行程式碼解決問題,但隨應用程式複雜度增加,這類「單行修補」會失控,難以維護。
public class Person : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propName) {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
public string Name { get => name; set { name = value; OnPropertyChanged("Name"); } }
public int Age { get => age; set { age = value; OnPropertyChanged("Age"); } }
}
person.PropertyChanged += person_PropertyChanged;
void person_PropertyChanged(object sender, PropertyChangedEventArgs e) {
switch (e.PropertyName) {
case "Name": nameTextBox.Text = person.Name; break;
case "Age": ageTextBox.Text = person.Age.ToString(); break;
}
}
現在 Person.Age 變更會自動觸發 UI 更新(圖 4-3、4-4),解決了「資料→UI」單向同步。
但使用者在 TextBox 輸入新名稱時,Person 物件不會更新(圖 4-5)。需處理 TextBox.TextChanged 事件回寫物件(範例 4-7):
nameTextBox.TextChanged += (s, e) => person.Name = nameTextBox.Text;
ageTextBox.TextChanged += (s, e) => { if (int.TryParse(ageTextBox.Text, out int age)) person.Age = age; };
現在雙向同步完成(圖 4-6),但付出的代價是:
這正是「資料繫結」機制誕生的原因——以優雅、少量的程式碼取代大量重複的手動同步邏輯,自動處理雙向同步、型別轉換、變更通知。
