c# - 使用过滤器在绑定的 DataGridView 中保存更改
问题描述
我有一个由 BindingSource 填充的 DataGridView。每次用户修改一行并且他/她移动到另一行(每次修改的行失去焦点)它都会触发事件RowValidated
。
在这种情况下,DataGridView.CurrentRow
使用存储过程在 SQLServer 中修改元素。
当 BindingSource 有一个过滤器处于活动状态时,这种方法不会。因为如果修改了被过滤列的单元格,则行分散器(由于过滤器)和我的方法将其捕获DataGridView.CurrentRow
为下一个。
我不能使用该方法TableAdapter.Update()
,因为 DataSet 是多个表的连接并且它不会自动生成。
在过滤器效果之前是否有任何事件被触发?我会接受任何不同的方法作为答案。
编辑:当一个单元格被修改时,保存在一个列表中的那一行的 ID 值。里面的代码RowValidated
封装在
if(ListOfIds.Contains(DataGridView.CurrentRow.Cells["ID"])){StoredProcedure();}
解决方案
自己读取和写入单元格的值很少是一个好主意。使用 DataBinding 通常是一种更简单的方法。
似乎您已经使用了 BindingSource,但由于某种原因,您从显示的数据中读取了更改的行,而不是从原始 BindingSource 中读取。
我不确定一旦操作员移动到新行就更新数据库是否明智。如果他不知道要填写的值,想向下滚动查看另一行怎么办?考虑更改界面,以便操作员可以指示他已完成所有数据的编辑。例如一个按钮。但这有点超出你的问题。
如果您将数据放在BindingList中,并将此数据分配给 DataGridView 的 DataSource,那么 DataGridView 中数据的每次更改都会在 BindingList 中自动更新。使用事件BindingList.ListChanged获得通知,或在处理更改的数据之前使用上述按钮。
BindingList<Customer> DisplayedCustomers {get; } = new BindingList<Customer>();
public MyForm()
{
this.InitializeComponents();
this.DataGridView1.DataSource = this.DisplayedCustomers();
this.BindingListView.ListChanged += BindingListChanged;
}
显示一个空的 DataGridView。填写客户:
private InitializeDataGridView()
{
IEnumerable<Customer> customers = this.QueryCustomers();
foreach (var customer in Customers)
this.Customers.Add(customer);
}
这将自动显示您的 DataGridView 中的所有客户。唉,每个客户您将获得一次该活动。如果您不希望这样,请考虑创建一个新的 BindingList 并将其分配给 DataGridView 的 DataSource。不要忘记取消订阅旧的 BindingList 并订阅新的 BindingList 的事件
private void BindingListChanged(object sender, ListChangedEventArgs e)
{
BindingList<Customer> bindingList = (BindingList<Customer>)sender;
// use e.ListChangedType to detect what has changed:
// item added / removed / moved to a new location / value changed?
switch (e.ListChangedType)
{
case ListChangedType.ItemChanged:
var changedCustomer = bindingList[e.NewIndex];
ProcessChangedCustomer(changeCustomer);
break;
case ...
}
}
使用 BindingList 而不是摆弄 DataGridView 的单元格的值的优点是,您可以将数据与该数据与操作员的通信方式分离。这使得重用变得更容易(在 ComboBox 而不是 DataGridView 中显示它?继续吧,变化很小),更容易进行单元测试:如果没有表单,BindingList 也可以工作;因此更易于维护和更改。
最后一个建议:为了便于过滤属性(仅显示居住在纽约的客户),并简化排序,请考虑使用 nuget 包Equin.ApplicationFramework.BindingListView
List<Customer> customers = GetCustomers();
BindingListView<Customer> view = new BindingListView<Customer>(customers);
dataGridView1.DataSource = view;
和宾果游戏:通过鼠标单击列标题自由排序。它甚至会记住是升序还是降序排序,并显示排序字形(指示排序方向的箭头)。
过滤:
void FilerCustomersByCity(string city)
{
view.ApplyFilter(delegate(Customer) customer => customer.City == city);
}
推荐阅读
- angular - 如果 Angular 的本地存储中有数据,如何将默认主页路径“”更改为不同的路由
- javascript - 在 Playwright 中使用关键字数组并循环遍历脚本
- spring - spring-boot中如何实现行级授权?
- excel - Excel VBA:如何让 COUNTIF 函数不将文本单元格“1.1”和“1.10”作为重复项?
- configuration - Hue 和 Impala 连接问题 Thrift Handle 异常
- python - Pymongo 和更新记录
- node.js - 未找到模块:错误:无法解析 'D:\laravel projects\codeGram\resources\js\components' 中的 '../../../vue-temp/vue-editor-bridge'
- r - 如何获得这些由“;”分隔的字符串的唯一出现?
- python-3.x - 如何在 Docker PUSH 中排除 VENV
- amazon-web-services - 在 AWS SWF 工作流程中安排的计时器是否会无法返回时钟?