WinForms DevExpress绑定DataTable遇异常及绑定方式与事件问题咨询
WinForms DataTable绑定相关问题
我熟悉WPF的绑定机制,但WinForms的绑定总感觉摸不透。把DataTable绑定到多个控件时,碰到了整个窗体绑定失效的异常,于是试了四种绑定方式:
- 绑定到DataTable
comboBox.DataBindings.Add(new Binding("EditValue", dTable, "FieldName", true, DataSourceUpdateMode.OnPropertyChanged));
- 绑定到DataSet
comboBox.DataBindings.Add(new Binding("EditValue", dsData, "TableName.FieldName", true, DataSourceUpdateMode.OnPropertyChanged));
- 绑定到DataView
comboBox.DataBindings.Add(new Binding("EditValue", dsData.Tables["Table"].DefaultView, "FieldName", true, DataSourceUpdateMode.OnPropertyChanged));
- 通过中间BindingSource绑定
BindingSource bs = new BindingSource(); bs.DataSource = dsData.Tables["Table"]; comboBox.DataBindings.Add(new Binding("EditValue", bs, "FieldName", true, DataSourceUpdateMode.OnPropertyChanged));
为了维护值之间的依赖关系,我给DataTable加了ColumnChanged和RowChanged事件处理程序,但在这些回调里修改数据行时,绑定变得极不稳定。移除这些事件处理程序后,上面四种绑定方式都能正常工作,用DataSourceUpdateMode.OnValidation模式也没问题。
现在有两个问题:
- 这四种绑定方式是不是完全等价?我觉得BindingSource应该有额外的作用。
- 在ColumnChanged或RowChanged处理程序里修改底层数据会不会破坏绑定?我本来想通过这些事件把DataTable当“可观察模型”来感知数据变化。
问题解答
1. 四种绑定方式是否等价?
这四种方式不完全等价,BindingSource确实有不可替代的额外价值:
- 前三种方式(直接绑DataTable/DataSet/DataView)本质上都是直接和ADO.NET的数据源绑定,底层会自动创建一个隐藏的BindingSource来处理绑定逻辑,但你无法直接控制这个隐藏对象。
- 显式使用BindingSource的好处包括:
- 提供排序、筛选、分页的便捷接口,不用直接操作DataView;
- 自动处理数据源的变更通知转发,避免绑定直接感知数据源底层变化时的冲突;
- 支持嵌套绑定和复杂数据源的层级管理;
- 提供了CurrencyManager的封装,方便统一管理多控件的当前记录同步,避免多控件绑定同一数据源时出现状态不一致。
2. ColumnChanged/RowChanged回调修改数据是否会破坏绑定?
是的,这种操作很容易导致绑定不稳定甚至失效,原因在于:
- ColumnChanged和RowChanged事件是在DataRow的数据变更已经完成后触发的,如果你在回调里再次修改同一行的数据,会触发新一轮的ColumnChanged/RowChanged事件,形成递归触发的死循环(即使加了判断,也可能导致绑定的UI频繁刷新,出现闪烁、响应延迟甚至崩溃)。
- WinForms的绑定机制依赖于数据源的变更通知,但在事件回调中修改数据会打乱绑定的更新时序:绑定控件刚接收到变更通知准备更新UI,数据源又发生了新的变更,导致UI和数据源的状态同步混乱。
如果想把DataTable作为可观察模型来维护值依赖,建议换一种方式:
- 不要在ColumnChanged/RowChanged事件里直接修改数据,而是改用DataTable的ColumnChanging/RowChanging事件(这两个事件是在数据变更发生前触发的),在变更前校验或修改值,避免递归触发;
- 或者显式使用BindingSource,把值依赖的逻辑放在BindingSource的CurrentChanged或ListChanged事件里,利用BindingSource的事件转发机制来避免直接操作DataTable的变更事件导致的冲突;
- 如果逻辑复杂,也可以封装一个独立的视图模型类,把DataTable的数据映射到模型中,通过模型的INotifyPropertyChanged接口来通知UI变更,这样更符合MVVM的思路,也能避免直接操作DataTable事件带来的问题。
内容的提问来源于stack exchange,提问作者Congenital Optimist
相关产品推荐
相关产品推荐

