级联绑定DataGridView点击Link_Contract_Letting行时Deses视图不更新
场景说明
现有3层通过BindingSource实现关联的主从DataGridView(简称dgv)控件,各表均配置了对应的BindingSource,表结构关系参考:
表结构关系示意图
三层绑定层级为:Link_Contract_Letting → Contracts → Deses
异常表现
- 点击
Link_Contract_Letting对应的dgv行时,关联的Contractsdgv可正常更新 - 但
Desesdgv不会同步刷新,只有手动点击Contractsdgv的行时,Desesdgv才会正常更新 - 预期效果:点击
Link_Contract_Lettingdgv行时Desesdgv自动同步更新
已尝试的无效方案
方案1:过滤Contracts绑定源
string contId = dgvLinks.SelectedCells[0].Value.ToString(); bsContracts.Filter = $"ContId IN ({string.Join(", ", contId)})";
存在问题:可以展示对应合同并过滤Deses数据,但会过滤掉当前Letting关联的其他合同,导致无法查看同Letting下的其他关联合同。
方案2:直接过滤Deses绑定源
string contId = dgvLinks.SelectedCells[0].Value.ToString(); bsDeses.Filter = $"ContId = " + contId;
存在问题:代码运行无报错但完全不生效,后续追加调用Refresh()、EndEdit()方法均未解决问题。
根因分析
WinForm原生主从BindingSource的同步逻辑为:从表绑定源仅响应直接父级绑定源的当前项(Current)变更事件,不会自动响应跨层级的祖父级数据源选中变化。
点击Link表dgv时,bsContracts虽然刷新了关联的合同列表,但不会自动触发当前项变更通知,因此绑定bsContracts作为父级的bsDeses不会感知到数据更新,自然不会刷新。手动点击Contracts dgv行时,本质是手动修改了bsContracts的Position属性、触发了Current变更,因此Deses表才会正常加载。
修复方案
不需要手动给任意从表BindingSource设置Filter,保持三层原生主从绑定配置即可:
- 确认三层绑定配置正确:
bsLinks的DataSource设置为Link_Contract_Letting对应的表/数据集bsContracts的DataSource设置为bsLinks,DataMember设置为Link表和Contracts表之间配置的DataRelation名称bsDeses的DataSource设置为bsContracts,DataMember设置为Contracts表和Deses表之间配置的DataRelation名称
- 为Link表对应的dgv控件添加
SelectionChanged事件处理,选中Link行后主动触发bsContracts的当前项变更,代码如下:
private void dgvLinks_SelectionChanged(object sender, EventArgs e) { // 校验选中状态和数据源有效性,避免空引用异常 if (dgvLinks.CurrentRow == null || bsContracts.Count <= 0) { return; } // 主动设置Contracts绑定源的选中位置,触发Current变更,驱动Deses表自动同步 // 默认选中当前Letting下的第一条合同,可按需修改Position值选中指定合同 bsContracts.Position = 0; }
如果需要切换Link行时默认选中Contracts列表中指定ContId的合同,只需要遍历bsContracts列表找到对应项的索引,将bsContracts.Position赋值为该索引即可,原生主从绑定机制会自动完成Deses表的数据过滤和刷新,不需要手动操作bsDeses的Filter属性。
内容的提问来源于stack exchange,提问作者SerialCoder

