C# .NET 6中如何让SynchronizedCollection具备可观察性以更新文本控件?
实现建议
方案1:包装SynchronizedCollection,添加自定义通知事件
既然SynchronizedCollection本身线程安全,我们可以通过继承它扩展通知能力,在集合修改操作完成后触发自定义事件,以此感知新项添加:
- 自定义子类继承
SynchronizedCollection<SomeClass>,重写Add、Insert等核心修改方法 - 在方法执行完成后,触发自定义的
ItemAdded事件(也可实现更通用的CollectionChanged事件) - 订阅事件后,在处理逻辑中切换到UI线程更新文本控件(比如WPF用
Dispatcher.Invoke,WinForms用Control.Invoke)
示例代码片段:
public class NotifiableSynchronizedCollection<T> : SynchronizedCollection<T> { public event EventHandler<T> ItemAdded; protected override void InsertItem(int index, T item) { base.InsertItem(index, item); ItemAdded?.Invoke(this, item); } protected override void AddItem(T item) { base.AddItem(item); ItemAdded?.Invoke(this, item); } } // 使用示例 var collection = new NotifiableSynchronizedCollection<SomeClass>(); collection.ItemAdded += (sender, newItem) => { Dispatcher.Invoke(() => txtLatestItem.Text = newItem.ToString()); };
方案2:替换为线程安全的ObservableCollection
ObservableCollection自带CollectionChanged事件,但本身非线程安全,可改造出兼顾线程安全与可观察性的版本:
- 自定义
ThreadSafeObservableCollection继承ObservableCollection<SomeClass> - 重写所有修改方法(Add/Insert/Remove等),用
lock保证线程安全 - 触发
CollectionChanged事件时,确保逻辑在UI线程执行(通过Dispatcher或SynchronizationContext)
示例代码片段:
public class ThreadSafeObservableCollection<T> : ObservableCollection<T> { private readonly object _lock = new object(); public new void Add(T item) { lock (_lock) { base.Add(item); } } protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { Dispatcher.CurrentDispatcher.Invoke(() => base.OnCollectionChanged(e)); } } // 使用示例 var collection = new ThreadSafeObservableCollection<SomeClass>(); collection.CollectionChanged += (sender, e) => { if (e.Action == NotifyCollectionChangedAction.Add && e.NewItems.Count > 0) { var newItem = (SomeClass)e.NewItems[0]; txtLatestItem.Text = newItem.ToString(); } };
方案3:定时轮询监控集合变化
如果不想修改现有集合结构,可采用轮询方式定期检查最新项:
- 用
DispatcherTimer(WPF)或System.Timers.Timer设置定时任务 - 每次触发时,借助
SynchronizedCollection的SyncRoot加锁读取,对比当前最后一项与之前记录的项,若不同则更新文本控件
示例代码片段:
var timer = new DispatcherTimer(); timer.Interval = TimeSpan.FromMilliseconds(500); SomeClass lastItem = null; timer.Tick += (sender, e) => { lock (collection.SyncRoot) { if (collection.Count > 0 && collection.Last() != lastItem) { lastItem = collection.Last(); txtLatestItem.Text = lastItem.ToString(); } } }; timer.Start();
内容的提问来源于stack exchange,提问作者krs
相关产品推荐
相关产品推荐

