当 INotifyPropertyChanged 碰上 BindingList 后跨线程问题
2025-10-18 15:15:46
#.NET
当INotifyPropertyChanged
和BindingList
搭配时,控件如果在编辑状态时收到数据变化通知则会引发异常


复现代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| using System.ComponentModel; using System.Runtime.CompilerServices;
namespace WinFormsApp1;
public class People : INotifyPropertyChanged { private int _age; public int Age { get => _age; set { if (_age == value) return;
_age = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string? propertyName = null) { if (EqualityComparer<T>.Default.Equals(field, value)) return false; field = value; OnPropertyChanged(propertyName); return true; } }
public partial class Form1 : Form { private readonly IList<People> _peoples = [];
public Form1() { InitializeComponent(); }
private void Form1_Load(object sender, EventArgs e) { _peoples.Add(new People {Age = 5});
dataGridView1.Columns[0].DataPropertyName = nameof(People.Age); dataGridView1.DataSource = new BindingList<People>(_peoples); }
private void button1_Click(object sender, EventArgs e) { Task.Run(() => { Thread.Sleep(2000); _peoples[0].Age = 10; }); } }
|
一个优雅的解决方案是实现线程安全的SynchronizedBindingList
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| internal sealed class SynchronizedBindingList<T>(IList<T> list) : BindingList<T>(list) { private readonly SynchronizationContext? _context = SynchronizationContext.Current;
protected override void OnListChanged(ListChangedEventArgs e) { if (_context != null && SynchronizationContext.Current != _context) { _context.Post(state => base.OnListChanged((state as ListChangedEventArgs)!), e); } else { base.OnListChanged(e); } } }
|
2025-10-18 15:15:46
#.NET