NavisworksTransport/src/UI/WPF/Collections/ThreadSafeObservableCollection.cs

615 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using System.Windows.Data;
using NavisworksTransport.Core;
using NavisworksTransport.Utils;
using NavisworksTransport.UI.WPF.Services;
namespace NavisworksTransport.UI.WPF.Collections
{
/// <summary>
/// 线程安全的ObservableCollection实现
/// 专门为WPF数据绑定场景设计支持跨线程操作和批量更新
///
/// 主要特性:
/// 1. 线程安全的集合操作,防止并发修改异常
/// 2. 自动UI线程同步确保PropertyChanged和CollectionChanged事件在UI线程触发
/// 3. 批量操作优化减少UI更新频率
/// 4. 集成UIStateManager进行统一的线程安全管理
/// </summary>
/// <typeparam name="T">集合元素类型</typeparam>
public class ThreadSafeObservableCollection<T> : ObservableCollection<T>
{
#region
private readonly object _lock = new object();
private readonly SynchronizationContext _synchronizationContext;
private volatile bool _suppressNotification = false;
private readonly DataBindingPerformanceMonitor _performanceMonitor;
/// <summary>
/// 获取当前是否正在批量更新中(禁用通知)
/// </summary>
public bool IsBatchUpdating => _suppressNotification;
/// <summary>
/// 获取当前集合元素数量(线程安全)
/// </summary>
public new int Count
{
get
{
lock (_lock)
{
return base.Count;
}
}
}
#endregion
#region
/// <summary>
/// 初始化线程安全的ObservableCollection
/// </summary>
public ThreadSafeObservableCollection()
: base()
{
_synchronizationContext = SynchronizationContext.Current;
_performanceMonitor = DataBindingPerformanceMonitor.Instance;
// 启用WPF集合同步机制
BindingOperations.EnableCollectionSynchronization(this, _lock);
LogManager.Debug($"ThreadSafeObservableCollection<{typeof(T).Name}>已初始化");
}
/// <summary>
/// 使用指定的初始元素初始化线程安全的ObservableCollection
/// </summary>
/// <param name="collection">初始元素集合</param>
public ThreadSafeObservableCollection(IEnumerable<T> collection)
: base(collection)
{
_synchronizationContext = SynchronizationContext.Current;
_performanceMonitor = DataBindingPerformanceMonitor.Instance;
// 启用WPF集合同步机制
BindingOperations.EnableCollectionSynchronization(this, _lock);
LogManager.Debug($"ThreadSafeObservableCollection<{typeof(T).Name}>已初始化,包含{Count}个元素");
}
#endregion
#region
/// <summary>
/// 线程安全的添加元素
/// </summary>
/// <param name="item">要添加的元素</param>
public new void Add(T item)
{
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
lock (_lock)
{
base.Add(item);
}
}
/// <summary>
/// 线程安全的插入元素
/// </summary>
/// <param name="index">插入位置</param>
/// <param name="item">要插入的元素</param>
public new void Insert(int index, T item)
{
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
lock (_lock)
{
base.Insert(index, item);
}
}
/// <summary>
/// 线程安全的移除元素
/// </summary>
/// <param name="item">要移除的元素</param>
/// <returns>是否成功移除</returns>
public new bool Remove(T item)
{
lock (_lock)
{
return base.Remove(item);
}
}
/// <summary>
/// 线程安全的移除指定位置的元素
/// </summary>
/// <param name="index">要移除的元素位置</param>
public new void RemoveAt(int index)
{
lock (_lock)
{
base.RemoveAt(index);
}
}
/// <summary>
/// 线程安全的清空集合
/// </summary>
public new void Clear()
{
lock (_lock)
{
base.Clear();
}
}
/// <summary>
/// 线程安全的元素访问
/// </summary>
/// <param name="index">元素索引</param>
/// <returns>指定位置的元素</returns>
public new T this[int index]
{
get
{
lock (_lock)
{
return base[index];
}
}
set
{
lock (_lock)
{
base[index] = value;
}
}
}
#endregion
#region
/// <summary>
/// 批量添加元素(原子操作)
/// 所有元素添加完成后才触发一次CollectionChanged事件
/// </summary>
/// <param name="items">要添加的元素集合</param>
public void AddRange(IEnumerable<T> items)
{
if (items == null)
{
throw new ArgumentNullException(nameof(items));
}
var itemList = items.ToList();
if (itemList.Count == 0)
{
return;
}
using (_performanceMonitor.BeginCollectionUpdate(typeof(ThreadSafeObservableCollection<T>), "AddRange", itemList.Count))
{
lock (_lock)
{
try
{
// 禁用通知
_suppressNotification = true;
// 批量添加
foreach (var item in itemList)
{
if (item != null)
{
base.Add(item);
}
}
}
finally
{
// 恢复通知
_suppressNotification = false;
}
// 触发批量添加事件
OnCollectionChanged(new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Add,
itemList,
Count - itemList.Count));
}
}
LogManager.Debug($"ThreadSafeObservableCollection批量添加{itemList.Count}个元素");
}
/// <summary>
/// 批量移除元素(原子操作)
/// </summary>
/// <param name="items">要移除的元素集合</param>
/// <returns>实际移除的元素数量</returns>
public int RemoveRange(IEnumerable<T> items)
{
if (items == null)
{
throw new ArgumentNullException(nameof(items));
}
var itemList = items.ToList();
if (itemList.Count == 0)
{
return 0;
}
var removedItems = new List<T>();
lock (_lock)
{
try
{
// 禁用通知
_suppressNotification = true;
// 批量移除
foreach (var item in itemList)
{
if (base.Remove(item))
{
removedItems.Add(item);
}
}
}
finally
{
// 恢复通知
_suppressNotification = false;
}
// 如果有元素被移除,触发批量移除事件
if (removedItems.Count > 0)
{
OnCollectionChanged(new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Remove,
removedItems));
}
}
LogManager.Debug($"ThreadSafeObservableCollection批量移除{removedItems.Count}个元素");
return removedItems.Count;
}
/// <summary>
/// 清空并批量添加元素(原子操作)
/// 等效于先Clear()再AddRange()但只触发一次Reset事件
/// </summary>
/// <param name="items">新的元素集合</param>
public void ClearAndAddRange(IEnumerable<T> items)
{
if (items == null)
{
throw new ArgumentNullException(nameof(items));
}
var itemList = items.ToList();
lock (_lock)
{
try
{
// 禁用通知
_suppressNotification = true;
// 清空现有元素
base.Clear();
// 添加新元素
foreach (var item in itemList)
{
if (item != null)
{
base.Add(item);
}
}
}
finally
{
// 恢复通知
_suppressNotification = false;
}
// 触发重置事件
OnCollectionChanged(new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Reset));
}
LogManager.Debug($"ThreadSafeObservableCollection重置并添加{itemList.Count}个元素");
}
/// <summary>
/// 批量更新操作的安全执行方法
/// 在指定的操作期间禁用集合变更通知操作完成后触发Reset事件
/// </summary>
/// <param name="batchOperation">批量操作委托</param>
public void ExecuteBatchUpdate(Action<ThreadSafeObservableCollection<T>> batchOperation)
{
if (batchOperation == null)
{
throw new ArgumentNullException(nameof(batchOperation));
}
lock (_lock)
{
try
{
// 禁用通知
_suppressNotification = true;
// 执行批量操作
batchOperation(this);
}
finally
{
// 恢复通知
_suppressNotification = false;
}
// 触发重置事件通知UI重新绑定
OnCollectionChanged(new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Reset));
}
LogManager.Debug("ThreadSafeObservableCollection批量更新操作完成");
}
#endregion
#region
/// <summary>
/// 重写集合变更事件处理确保在UI线程中触发
/// </summary>
/// <param name="e">集合变更事件参数</param>
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
// 如果正在批量更新,跳过通知
if (_suppressNotification)
{
return;
}
try
{
// 如果当前在UI线程直接触发事件
if (UIStateManager.Instance.IsUIThread)
{
base.OnCollectionChanged(e);
}
else
{
// 异步切换到UI线程触发事件
UIStateManager.Instance.QueueUIUpdate(() =>
{
try
{
base.OnCollectionChanged(e);
}
catch (Exception ex)
{
LogManager.Error($"ThreadSafeObservableCollection事件通知失败: {ex.Message}");
}
});
}
}
catch (Exception ex)
{
LogManager.Error($"ThreadSafeObservableCollection OnCollectionChanged异常: {ex.Message}");
// 关键异常,直接抛出
throw;
}
}
/// <summary>
/// 重写属性变更事件处理确保在UI线程中触发
/// </summary>
/// <param name="e">属性变更事件参数</param>
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
try
{
// 如果当前在UI线程直接触发事件
if (UIStateManager.Instance.IsUIThread)
{
base.OnPropertyChanged(e);
}
else
{
// 异步切换到UI线程触发事件
UIStateManager.Instance.QueueUIUpdate(() =>
{
try
{
base.OnPropertyChanged(e);
}
catch (Exception ex)
{
LogManager.Error($"ThreadSafeObservableCollection属性变更通知失败: {ex.Message}");
}
});
}
}
catch (Exception ex)
{
LogManager.Error($"ThreadSafeObservableCollection OnPropertyChanged异常: {ex.Message}");
// 非关键异常,记录但不抛出
}
}
#endregion
#region 线
/// <summary>
/// 线程安全的包含性检查
/// </summary>
/// <param name="item">要检查的元素</param>
/// <returns>集合是否包含指定元素</returns>
public new bool Contains(T item)
{
lock (_lock)
{
return base.Contains(item);
}
}
/// <summary>
/// 线程安全的索引查找
/// </summary>
/// <param name="item">要查找的元素</param>
/// <returns>元素的索引,如果不存在返回-1</returns>
public new int IndexOf(T item)
{
lock (_lock)
{
return base.IndexOf(item);
}
}
/// <summary>
/// 线程安全的元素复制
/// </summary>
/// <param name="array">目标数组</param>
/// <param name="arrayIndex">起始索引</param>
public new void CopyTo(T[] array, int arrayIndex)
{
lock (_lock)
{
base.CopyTo(array, arrayIndex);
}
}
/// <summary>
/// 线程安全的枚举器获取
/// 注意:枚举期间建议避免修改集合
/// </summary>
/// <returns>线程安全的枚举器</returns>
public new IEnumerator<T> GetEnumerator()
{
lock (_lock)
{
// 创建当前集合的快照用于枚举
var snapshot = this.ToList();
return snapshot.GetEnumerator();
}
}
/// <summary>
/// 获取集合的线程安全快照
/// </summary>
/// <returns>当前集合内容的快照列表</returns>
public List<T> ToSnapshot()
{
lock (_lock)
{
return this.ToList();
}
}
#endregion
#region
/// <summary>
/// 线程安全的条件查找
/// </summary>
/// <param name="predicate">查找条件</param>
/// <returns>第一个满足条件的元素如果不存在返回default(T)</returns>
public T FirstOrDefault(Func<T, bool> predicate)
{
if (predicate == null)
{
throw new ArgumentNullException(nameof(predicate));
}
lock (_lock)
{
return this.Where(predicate).FirstOrDefault();
}
}
/// <summary>
/// 线程安全的条件计数
/// </summary>
/// <param name="predicate">计数条件</param>
/// <returns>满足条件的元素数量</returns>
public int CountWhere(Func<T, bool> predicate)
{
if (predicate == null)
{
throw new ArgumentNullException(nameof(predicate));
}
lock (_lock)
{
return this.AsEnumerable().Where(predicate).Count();
}
}
/// <summary>
/// 线程安全的条件存在性检查
/// </summary>
/// <param name="predicate">检查条件</param>
/// <returns>是否存在满足条件的元素</returns>
public bool Any(Func<T, bool> predicate)
{
if (predicate == null)
{
throw new ArgumentNullException(nameof(predicate));
}
lock (_lock)
{
return this.Where(predicate).Any();
}
}
/// <summary>
/// 线程安全的条件过滤
/// </summary>
/// <param name="predicate">过滤条件</param>
/// <returns>满足条件的元素列表</returns>
public List<T> Where(Func<T, bool> predicate)
{
if (predicate == null)
{
throw new ArgumentNullException(nameof(predicate));
}
lock (_lock)
{
return this.AsEnumerable().Where(predicate).ToList();
}
}
#endregion
}
}