过滤BindingSource后如何保持DataGridView指定数据行持续为首个展示行
实现方案
核心逻辑:过滤、排序操作会导致DataTable的原始行索引和DataGridView的显示行索引不匹配,因此不要依赖DataTable的原始索引控制滚动位置,通过业务唯一标识(本场景为id列)在当前生效的绑定视图中查询实时索引,再设置首显行即可。
推荐实现(性能最优)
直接利用BindingSource的Find方法,该方法会直接在已经应用过滤、排序的当前视图中查询目标行的索引,返回的索引可直接赋值给DataGridView.FirstDisplayedScrollingRowIndex,无需遍历行,适合高频更新的场景。
代码示例
// 窗体初始化或BindingSource初始化时绑定ListChanged事件,列表变更自动触发定位 bindingSource1.ListChanged += (sender, e) => { // 仅在列表重置、行删除、行数据变更时执行定位,减少不必要的性能消耗 if (e.ListChangedType is ListChangedType.Reset or ListChangedType.ItemDeleted or ListChangedType.ItemChanged) { // 按唯一id查询目标行在当前过滤后视图中的索引,"id"替换为你实际的主键列名 int targetIndex = bindingSource1.Find("id", 300); // 索引有效时设置为首显行 if (targetIndex >= 0 && dataGridView1.FirstDisplayedScrollingRowIndex != targetIndex) { dataGridView1.FirstDisplayedScrollingRowIndex = targetIndex; } } };
兼容实现(适配自定义校验场景)
如果你需要对目标行做额外的自定义校验,可以遍历DataGridView当前的显示行匹配目标id:
// 每次数据刷新/过滤应用后执行 int targetIndex = -1; int targetId = 300; foreach (DataGridViewRow row in dataGridView1.Rows) { if (row.Cells["id"].Value != null && Convert.ToInt32(row.Cells["id"].Value) == targetId) { targetIndex = row.Index; break; } } if (targetIndex >= 0) { dataGridView1.FirstDisplayedScrollingRowIndex = targetIndex; }
内容的提问来源于stack exchange,提问作者user3584783
相关产品推荐
相关产品推荐

