数据绑定基础笔记
数据绑定是 WPF 里和传统 WinForms 差别最大的地方。WinForms 习惯是在事件里手动给控件赋值,WPF 则是把控件属性和数据对象的属性关联起来,数据变了界面自动更新。
1. 最基本的写法
<TextBox Text="{Binding UserName}" />
这里 UserName 是从当前元素的 DataContext 上找的属性。DataContext 会沿着可视树向下继承,所以通常在窗口或某个容器上设置一次即可:
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
2. 绑定模式
OneWay:数据 → 界面,只读展示用,例如 TextBlock。TwoWay:数据 ↔ 界面,输入控件用,例如 TextBox、CheckBox。OneTime:只在初始化时取一次值,之后不再更新。OneWayToSource:界面 → 数据,用得比较少。
大部分控件都有合理的默认模式,TextBox.Text 默认就是 TwoWay,TextBlock.Text 默认是 OneWay,一般不需要显式写。
3. 界面不刷新,先查 INotifyPropertyChanged
这是我遇到最多的一个问题:给属性赋了新值,但界面没有任何变化。原因是绑定的数据对象没有通知界面“我变了”。数据类需要实现 INotifyPropertyChanged:
public class MainViewModel : INotifyPropertyChanged
{
private string _userName;
public string UserName
{
get => _userName;
set
{
if (_userName == value) return;
_userName = value;
OnPropertyChanged(nameof(UserName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
注意:属性必须是 public 属性,字段和私有属性都绑不上。另外集合发生增删时,要用 ObservableCollection<T> 而不是 List<T>,否则列表界面同样不会更新。
4. 几个常用的绑定参数
StringFormat:格式化显示,例如{Binding Price, StringFormat=C}按货币格式输出。Converter:需要类型转换或条件判断时,实现IValueConverter。UpdateSourceTrigger=PropertyChanged:让 TextBox 每次按键都回写数据,默认是失去焦点时才回写。ElementName/RelativeSource:绑定到另一个控件或父级元素,而不是 DataContext。
5. 调试技巧
绑定写错时不会抛异常,只是界面上什么都不显示,比较难查。两个办法:一是看 Visual Studio 的“输出”窗口,绑定失败会打印 System.Windows.Data Error 的提示,里面会写清楚在哪个对象上找不到哪个属性;二是给绑定加上 PresentationTraceSources.TraceLevel=High,输出更详细的过程。