615 lines
18 KiB
C#
615 lines
18 KiB
C#
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
|
||
}
|
||
} |