WinForms中BindingList<T>是否需结合BindingSource或INotifyPropertyChanged?
是否需要使用BindingSource和INotifyPropertyChanged?
两者都不是必须的,但你的代码确实能从它们身上获得不少好处,下面分别拆解说明:
一、关于BindingSource
你当前直接把BindingList<Item>赋值给ListBox的DataSource,确实能实现列表增删改的同步,但引入BindingSource能带来这些提升:
- 简化选中项操作:不用再通过
listBox1.SelectedIndex去取Items[index],直接用bindingSource.Current就能拿到当前选中的Item,代码更简洁。 - 支持筛选、排序:如果以后需要给列表加筛选(比如只显示ID大于5的项)或排序,直接设置
bindingSource.Filter和bindingSource.Sort属性就行,不用自己手动处理集合。 - 多控件同步绑定:要是后续加个TextBox显示选中Item的名称、Label显示ID,直接把这些控件的
DataSource设为同一个BindingSource,就能自动和ListBox的选中项同步,不用写SelectedIndexChanged事件手动更新控件。 - 避免重复绑定的闪烁问题:如果以后需要重置数据源,用BindingSource的话,只需要更新它的
DataSource,控件不会频繁刷新导致闪烁。
给你改个用BindingSource的示例片段:
private BindingSource bindingSource; public Form1() { InitializeComponent(); Items = new BindingList<Item>(/* 你的初始数据 */); bindingSource = new BindingSource(); bindingSource.DataSource = Items; } private void Form1_Load(object sender, EventArgs e) { listBox1.DataSource = bindingSource; } // 修改EditButton_Click private void EditButton_Click(object sender, EventArgs e) { var selectedItem = bindingSource.Current as Item; if (selectedItem != null) { EditForm form = new() { Item = selectedItem }; if (form.ShowDialog() == DialogResult.OK && form.Item != null) { // 如果Item实现了INotifyPropertyChanged,这里直接修改属性就会同步,不用替换整个对象 // selectedItem.Name = form.Item.Name; // selectedItem.Id = form.Item.Id; // ... // 现在你的逻辑是替换对象,也可以这么写: int index = bindingSource.Position; Items[index] = form.Item; } } VerifyList(); }
二、关于INotifyPropertyChanged
你当前的代码能正常工作,是因为每次编辑都是替换整个Item对象(Items[index] = form.Item),这种操作会触发BindingList的ListChanged事件,ListBox会更新显示。但如果你的编辑逻辑改成直接修改原Item的属性(比如在EditForm里直接修改传入的Item的Name、Id,而不是返回新对象),那ListBox不会自动更新——因为BindingList只监听集合的结构变化(增删项、替换项),不监听单个Item内部属性的变化。
这时候就需要让Item类实现INotifyPropertyChanged接口,当属性值变化时触发PropertyChanged事件,这样BindingList(或BindingSource)就能捕捉到变化,自动同步到ListBox。
示例Item类实现:
public class Item : INotifyPropertyChanged { private string _name; private int _id; private DateTime _date; public Item(string name, int id, DateTime date) { _name = name; _id = id; _date = date; } public string Name { get => _name; set { if (_name != value) { _name = value; OnPropertyChanged(nameof(Name)); } } } public int Id { get => _id; set { if (_id != value) { _id = value; OnPropertyChanged(nameof(Id)); } } } public DateTime Date { get => _date; set { if (_date != value) { _date = value; OnPropertyChanged(nameof(Date)); } } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } // 重写ToString,让ListBox显示正确的文本 public override string ToString() { return $"{Name} (ID: {Id})"; } }
有了这个实现,以后你在EditForm里直接修改原Item的属性,ListBox会自动刷新显示,不用再替换整个对象,代码更高效。
总结
- 如果你的需求一直停留在当前的增删改(替换对象),那不用改也能正常用,但加BindingSource能让代码更灵活,方便后续扩展。
- 如果以后要支持修改Item属性后自动更新UI,那必须实现INotifyPropertyChanged。
内容的提问来源于stack exchange,提问作者Jonathan Wood
相关产品推荐
相关产品推荐

