C# DataGridView无法正确更新问题求助
这个问题我太熟了——WinForms的DataGridView和普通List<T>绑定的时候,会踩一个经典的坑:List<T>没有实现数据变更通知接口。
第一次绑定的时候,DataGridView会读取列表里的现有数据并显示,但之后你往List里添加新项,它不会主动告诉控件“我更新了”。哪怕你重新设置DataSource = orderitemlist,因为控件检测到数据源的引用没变化(还是同一个List对象),它就不会重新触发刷新逻辑,所以新添加的项就显示不出来。
下面给你两种靠谱的解决办法,推荐第一种,更符合WinForms数据绑定的最佳实践:
方法1:用BindingList<T>替代List<T>(推荐)
BindingList<T>是.NET专门为数据绑定设计的集合类型,它实现了IBindingList接口,当你添加、删除或者修改集合里的项时,会自动通知绑定的控件更新显示。
修改步骤:
- 把你的列表定义从
List<Models.OrderItem>改成BindingList<Models.OrderItem>:
// 原来的代码 // List<Models.OrderItem> orderitemlist = new List<Models.OrderItem>(); // 修改后 BindingList<Models.OrderItem> orderitemlist = new BindingList<Models.OrderItem>();
- 你的
RefreshItemsOnOrderData方法可以保留,甚至可以不用——因为BindingList会自动通知DataGridView更新,添加项后控件会立刻显示新内容:
private void RefreshItemsOnOrderData() { // 现在这行代码其实可以去掉,不过保留也不影响 ItemOnOrderDataGrid.DataSource = orderitemlist; }
这样修改后,你点击按钮添加新项,DataGridView会自动刷新显示新的OrderItem,不用再手动处理刷新逻辑。
方法2:强制刷新List<T>的绑定(临时方案)
如果你暂时不想换集合类型,也可以通过“先清空数据源再重新绑定”的方式强制DataGridView刷新:
修改你的RefreshItemsOnOrderData方法:
private void RefreshItemsOnOrderData() { // 先把数据源设为null,打破原有绑定 ItemOnOrderDataGrid.DataSource = null; // 再重新绑定列表 ItemOnOrderDataGrid.DataSource = orderitemlist; // 可选:如果列没有自动生成,可以打开自动生成列 ItemOnOrderDataGrid.AutoGenerateColumns = true; }
这种方法虽然能解决问题,但每次刷新都会重新创建列(如果开了自动生成),体验不如BindingList流畅,而且如果后续要支持修改项的属性自动更新,还是得用BindingList+INotifyPropertyChanged。
额外提示(可选)
如果之后你需要修改OrderItem的属性(比如修改数量),希望DataGridView自动显示修改后的值,那你的Models.OrderItem类需要实现INotifyPropertyChanged接口,示例如下:
public class OrderItem : INotifyPropertyChanged { private int _itemID; private string _itemname; private int _sellprice; private int _quantity; public int ItemID { get => _itemID; set { _itemID = value; OnPropertyChanged(nameof(ItemID)); } } // 其他属性同理,都要添加setter里的通知逻辑 public string ItemName { get => _itemname; set { _itemname = value; OnPropertyChanged(nameof(ItemName)); } } public int SellPrice { get => _sellprice; set { _sellprice = value; OnPropertyChanged(nameof(SellPrice)); } } public int Quantity { get => _quantity; set { _quantity = value; OnPropertyChanged(nameof(Quantity)); } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
内容的提问来源于stack exchange,提问作者Luke

