refactor: 完成 DataBindingPerformanceMonitor 功能的完整删除
- 删除 DataBindingPerformanceMonitor.cs 文件 - 从 NavisworksTransportPlugin.csproj 移除编译引用 - 清理 ViewModelBase.cs 中的所有性能监控代码 - 清理 ThreadSafeObservableCollection.cs 中的性能监控集成 - 清理 SmartDataBindingOptimizer.cs 中的性能监控使用 - 清理 BindingExpressionOptimizer.cs 中的性能监控调用 该功能不再需要,移除后简化了代码结构
This commit is contained in:
parent
821725d406
commit
b05bb727c6
@ -272,7 +272,6 @@
|
|||||||
|
|
||||||
<!-- UI - WPF Services -->
|
<!-- UI - WPF Services -->
|
||||||
<Compile Include="src\UI\WPF\Services\BindingExpressionOptimizer.cs" />
|
<Compile Include="src\UI\WPF\Services\BindingExpressionOptimizer.cs" />
|
||||||
<Compile Include="src\UI\WPF\Services\DataBindingPerformanceMonitor.cs" />
|
|
||||||
<Compile Include="src\UI\WPF\Services\SmartDataBindingOptimizer.cs" />
|
<Compile Include="src\UI\WPF\Services\SmartDataBindingOptimizer.cs" />
|
||||||
|
|
||||||
<!-- UI - WPF Commands and Models -->
|
<!-- UI - WPF Commands and Models -->
|
||||||
|
|||||||
@ -141,7 +141,7 @@ double WindingNumber(Point3d point);
|
|||||||
|
|
||||||
#### 应用场景
|
#### 应用场景
|
||||||
|
|
||||||
**场景 1:优化 GetPotentialColliders()**
|
场景 1:优化 GetPotentialColliders()**
|
||||||
|
|
||||||
当前实现(线性遍历):
|
当前实现(线性遍历):
|
||||||
|
|
||||||
@ -176,7 +176,7 @@ var potentialColliders = sceneTree.FindNearestTriangles(
|
|||||||
- 优化后:O(log n) ≈ log₂(290) ≈ 8 次树节点遍历
|
- 优化后:O(log n) ≈ log₂(290) ≈ 8 次树节点遍历
|
||||||
- **加速比**:约 36 倍
|
- **加速比**:约 36 倍
|
||||||
|
|
||||||
**场景 2:精确碰撞检测**
|
场景 2:精确碰撞检测**
|
||||||
|
|
||||||
替代简单包围盒检测,使用三角形级别的精确相交:
|
替代简单包围盒检测,使用三角形级别的精确相交:
|
||||||
|
|
||||||
@ -205,7 +205,7 @@ tree.Build(BuildStrategy.TopDownMidpoint);
|
|||||||
|
|
||||||
#### 技术挑战
|
#### 技术挑战
|
||||||
|
|
||||||
**挑战 1:Navisworks Geometry → DMesh3 转换**
|
挑战 1:Navisworks Geometry → DMesh3 转换
|
||||||
|
|
||||||
Navisworks 的 `ModelItem` 不直接暴露三角网格,需要通过几何提取:
|
Navisworks 的 `ModelItem` 不直接暴露三角网格,需要通过几何提取:
|
||||||
|
|
||||||
@ -266,7 +266,7 @@ List<T> FindPointsInBox(AxisAlignedBox3d box);
|
|||||||
|
|
||||||
#### 应用场景
|
#### 应用场景
|
||||||
|
|
||||||
**场景 1:加速动画碰撞检测**
|
场景 1:加速动画碰撞检测
|
||||||
|
|
||||||
当前问题:
|
当前问题:
|
||||||
|
|
||||||
@ -312,7 +312,7 @@ foreach (var obstacle in nearbyObstacles)
|
|||||||
- 优化后:每帧检测 5-15 个对象(仅邻近格子)
|
- 优化后:每帧检测 5-15 个对象(仅邻近格子)
|
||||||
- **加速比**:约 7-20 倍
|
- **加速比**:约 7-20 倍
|
||||||
|
|
||||||
**场景 2:动态场景更新**
|
场景 2:动态场景更新
|
||||||
|
|
||||||
支持障碍物动态添加/移动:
|
支持障碍物动态添加/移动:
|
||||||
|
|
||||||
@ -377,7 +377,7 @@ DistTriangle3Triangle3 // 三角形到三角形的距离
|
|||||||
|
|
||||||
#### 应用场景
|
#### 应用场景
|
||||||
|
|
||||||
**场景 1:精确碰撞容差**
|
场景 1:精确碰撞容差
|
||||||
|
|
||||||
当前问题:
|
当前问题:
|
||||||
|
|
||||||
@ -412,7 +412,7 @@ foreach (var triangle1 in animatedObjectMesh.Triangles)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**场景 2:碰撞报告增强**
|
场景 2:碰撞报告增强
|
||||||
|
|
||||||
在碰撞报告中显示:
|
在碰撞报告中显示:
|
||||||
|
|
||||||
@ -454,7 +454,7 @@ IntrRay3AxisAlignedBox3 // 射线-轴对齐盒相交
|
|||||||
|
|
||||||
#### 应用场景
|
#### 应用场景
|
||||||
|
|
||||||
**场景 1:路径可达性验证**
|
场景 1:路径可达性验证
|
||||||
|
|
||||||
检查两点间的直线路径是否被障碍物阻挡:
|
检查两点间的直线路径是否被障碍物阻挡:
|
||||||
|
|
||||||
@ -487,7 +487,7 @@ public bool IsPathClear(Point3D start, Point3D end, IEnumerable<DMesh3> obstacle
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**场景 2:视线检测**
|
场景 2:视线检测
|
||||||
|
|
||||||
判断两个物体之间是否有遮挡:
|
判断两个物体之间是否有遮挡:
|
||||||
|
|
||||||
@ -567,7 +567,7 @@ for (int i = 0; i < path.Count - 1; i++)
|
|||||||
|
|
||||||
### 5.1 整体架构
|
### 5.1 整体架构
|
||||||
|
|
||||||
```
|
```graph
|
||||||
┌─────────────────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
│ Navisworks API │
|
│ Navisworks API │
|
||||||
│ (ModelItem, BoundingBox3D, Geometry) │
|
│ (ModelItem, BoundingBox3D, Geometry) │
|
||||||
@ -1057,7 +1057,7 @@ private List<ModelItem> GetPotentialColliders()
|
|||||||
|
|
||||||
### 9.3 集成策略
|
### 9.3 集成策略
|
||||||
|
|
||||||
```
|
```graph
|
||||||
geometry3Sharp 基础库
|
geometry3Sharp 基础库
|
||||||
├── 体素网格模块 (用于路径规划)
|
├── 体素网格模块 (用于路径规划)
|
||||||
│ ├── MeshSignedDistanceGrid
|
│ ├── MeshSignedDistanceGrid
|
||||||
|
|||||||
@ -30,7 +30,6 @@ namespace NavisworksTransport.UI.WPF.Collections
|
|||||||
private readonly object _lock = new object();
|
private readonly object _lock = new object();
|
||||||
private readonly SynchronizationContext _synchronizationContext;
|
private readonly SynchronizationContext _synchronizationContext;
|
||||||
private volatile bool _suppressNotification = false;
|
private volatile bool _suppressNotification = false;
|
||||||
private readonly DataBindingPerformanceMonitor _performanceMonitor;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取当前是否正在批量更新中(禁用通知)
|
/// 获取当前是否正在批量更新中(禁用通知)
|
||||||
@ -62,11 +61,10 @@ namespace NavisworksTransport.UI.WPF.Collections
|
|||||||
: base()
|
: base()
|
||||||
{
|
{
|
||||||
_synchronizationContext = SynchronizationContext.Current;
|
_synchronizationContext = SynchronizationContext.Current;
|
||||||
_performanceMonitor = DataBindingPerformanceMonitor.Instance;
|
|
||||||
|
|
||||||
// 启用WPF集合同步机制
|
// 启用WPF集合同步机制
|
||||||
BindingOperations.EnableCollectionSynchronization(this, _lock);
|
BindingOperations.EnableCollectionSynchronization(this, _lock);
|
||||||
|
|
||||||
LogManager.Debug($"ThreadSafeObservableCollection<{typeof(T).Name}>已初始化");
|
LogManager.Debug($"ThreadSafeObservableCollection<{typeof(T).Name}>已初始化");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,11 +76,10 @@ namespace NavisworksTransport.UI.WPF.Collections
|
|||||||
: base(collection)
|
: base(collection)
|
||||||
{
|
{
|
||||||
_synchronizationContext = SynchronizationContext.Current;
|
_synchronizationContext = SynchronizationContext.Current;
|
||||||
_performanceMonitor = DataBindingPerformanceMonitor.Instance;
|
|
||||||
|
|
||||||
// 启用WPF集合同步机制
|
// 启用WPF集合同步机制
|
||||||
BindingOperations.EnableCollectionSynchronization(this, _lock);
|
BindingOperations.EnableCollectionSynchronization(this, _lock);
|
||||||
|
|
||||||
LogManager.Debug($"ThreadSafeObservableCollection<{typeof(T).Name}>已初始化,包含{Count}个元素");
|
LogManager.Debug($"ThreadSafeObservableCollection<{typeof(T).Name}>已初始化,包含{Count}个元素");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,36 +203,33 @@ namespace NavisworksTransport.UI.WPF.Collections
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using (_performanceMonitor.BeginCollectionUpdate(typeof(ThreadSafeObservableCollection<T>), "AddRange", itemList.Count))
|
lock (_lock)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
try
|
||||||
{
|
{
|
||||||
try
|
// 禁用通知
|
||||||
{
|
_suppressNotification = true;
|
||||||
// 禁用通知
|
|
||||||
_suppressNotification = true;
|
|
||||||
|
|
||||||
// 批量添加
|
// 批量添加
|
||||||
foreach (var item in itemList)
|
foreach (var item in itemList)
|
||||||
|
{
|
||||||
|
if (item != null)
|
||||||
{
|
{
|
||||||
if (item != null)
|
base.Add(item);
|
||||||
{
|
|
||||||
base.Add(item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
// 恢复通知
|
|
||||||
_suppressNotification = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 触发批量添加事件
|
|
||||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(
|
|
||||||
NotifyCollectionChangedAction.Add,
|
|
||||||
itemList,
|
|
||||||
Count - itemList.Count));
|
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// 恢复通知
|
||||||
|
_suppressNotification = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 触发批量添加事件
|
||||||
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(
|
||||||
|
NotifyCollectionChangedAction.Add,
|
||||||
|
itemList,
|
||||||
|
Count - itemList.Count));
|
||||||
}
|
}
|
||||||
|
|
||||||
LogManager.Debug($"ThreadSafeObservableCollection批量添加{itemList.Count}个元素");
|
LogManager.Debug($"ThreadSafeObservableCollection批量添加{itemList.Count}个元素");
|
||||||
|
|||||||
@ -25,9 +25,6 @@ namespace NavisworksTransport.UI.WPF.Services
|
|||||||
private readonly ConcurrentDictionary<string, CachedBindingValue> _bindingCache;
|
private readonly ConcurrentDictionary<string, CachedBindingValue> _bindingCache;
|
||||||
private readonly ConcurrentDictionary<BindingExpression, BindingMetadata> _bindingMetadata;
|
private readonly ConcurrentDictionary<BindingExpression, BindingMetadata> _bindingMetadata;
|
||||||
|
|
||||||
// 性能监控
|
|
||||||
private readonly DataBindingPerformanceMonitor _performanceMonitor;
|
|
||||||
|
|
||||||
// 优化配置
|
// 优化配置
|
||||||
private TimeSpan _cacheExpiration = TimeSpan.FromMinutes(5);
|
private TimeSpan _cacheExpiration = TimeSpan.FromMinutes(5);
|
||||||
private int _maxCacheSize = 1000;
|
private int _maxCacheSize = 1000;
|
||||||
@ -125,7 +122,6 @@ namespace NavisworksTransport.UI.WPF.Services
|
|||||||
_bindingCache = new ConcurrentDictionary<string, CachedBindingValue>();
|
_bindingCache = new ConcurrentDictionary<string, CachedBindingValue>();
|
||||||
_bindingMetadata = new ConcurrentDictionary<BindingExpression, BindingMetadata>();
|
_bindingMetadata = new ConcurrentDictionary<BindingExpression, BindingMetadata>();
|
||||||
_pendingUpdates = new HashSet<BindingExpression>();
|
_pendingUpdates = new HashSet<BindingExpression>();
|
||||||
_performanceMonitor = DataBindingPerformanceMonitor.Instance;
|
|
||||||
|
|
||||||
// 初始化批量更新定时器
|
// 初始化批量更新定时器
|
||||||
_batchUpdateTimer = new DispatcherTimer(DispatcherPriority.Background)
|
_batchUpdateTimer = new DispatcherTimer(DispatcherPriority.Background)
|
||||||
@ -292,10 +288,7 @@ namespace NavisworksTransport.UI.WPF.Services
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (_performanceMonitor.BeginPropertyUpdate(bindingExpression.Target?.GetType() ?? typeof(object), GetBindingPath(bindingExpression)))
|
bindingExpression.UpdateTarget();
|
||||||
{
|
|
||||||
bindingExpression.UpdateTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新元数据
|
// 更新元数据
|
||||||
if (_bindingMetadata.TryGetValue(bindingExpression, out var metadata))
|
if (_bindingMetadata.TryGetValue(bindingExpression, out var metadata))
|
||||||
@ -336,16 +329,13 @@ namespace NavisworksTransport.UI.WPF.Services
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (_performanceMonitor.BeginCollectionUpdate(typeof(BindingExpressionOptimizer), "BatchUpdate", updatesToProcess.Count))
|
// 按优先级和类型分组
|
||||||
{
|
var groupedUpdates = GroupUpdatesByPriority(updatesToProcess);
|
||||||
// 按优先级和类型分组
|
|
||||||
var groupedUpdates = GroupUpdatesByPriority(updatesToProcess);
|
|
||||||
|
|
||||||
// 按优先级顺序处理
|
// 按优先级顺序处理
|
||||||
foreach (var group in groupedUpdates.OrderByDescending(g => g.Key))
|
foreach (var group in groupedUpdates.OrderByDescending(g => g.Key))
|
||||||
{
|
{
|
||||||
ProcessUpdateGroup(group.Value);
|
ProcessUpdateGroup(group.Value);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LogManager.Debug($"批量更新完成: {updatesToProcess.Count}个绑定");
|
LogManager.Debug($"批量更新完成: {updatesToProcess.Count}个绑定");
|
||||||
|
|||||||
@ -1,695 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Threading;
|
|
||||||
|
|
||||||
namespace NavisworksTransport.UI.WPF.Services
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 数据绑定性能监控器 - 监控和分析WPF数据绑定的性能表现
|
|
||||||
/// 提供详细的性能指标收集和优化建议
|
|
||||||
/// </summary>
|
|
||||||
public class DataBindingPerformanceMonitor : IDisposable
|
|
||||||
{
|
|
||||||
#region 字段和属性
|
|
||||||
|
|
||||||
private static DataBindingPerformanceMonitor _instance;
|
|
||||||
private static readonly object _instanceLock = new object();
|
|
||||||
|
|
||||||
// 性能数据收集
|
|
||||||
private readonly ConcurrentDictionary<string, PropertyUpdateMetrics> _propertyMetrics;
|
|
||||||
private readonly ConcurrentDictionary<string, CollectionUpdateMetrics> _collectionMetrics;
|
|
||||||
private readonly ConcurrentQueue<BindingUpdateEvent> _updateEvents;
|
|
||||||
private readonly Timer _reportTimer;
|
|
||||||
private volatile bool _isDisposed = false;
|
|
||||||
private volatile bool _isMonitoringEnabled = true;
|
|
||||||
|
|
||||||
// 监控配置
|
|
||||||
private TimeSpan _reportInterval = TimeSpan.FromMinutes(5);
|
|
||||||
private int _maxEventHistory = 10000;
|
|
||||||
private int _performanceThresholdMs = 16; // 60FPS下每帧约16ms
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取性能监控器的单例实例
|
|
||||||
/// </summary>
|
|
||||||
public static DataBindingPerformanceMonitor Instance
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_instance == null)
|
|
||||||
{
|
|
||||||
lock (_instanceLock)
|
|
||||||
{
|
|
||||||
if (_instance == null)
|
|
||||||
{
|
|
||||||
_instance = new DataBindingPerformanceMonitor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return _instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否启用性能监控
|
|
||||||
/// </summary>
|
|
||||||
public bool IsMonitoringEnabled
|
|
||||||
{
|
|
||||||
get => _isMonitoringEnabled;
|
|
||||||
set => _isMonitoringEnabled = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 性能阈值(毫秒)- 超过此值的操作将被标记为慢操作
|
|
||||||
/// </summary>
|
|
||||||
public int PerformanceThresholdMs
|
|
||||||
{
|
|
||||||
get => _performanceThresholdMs;
|
|
||||||
set => _performanceThresholdMs = Math.Max(1, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前监控的属性数量
|
|
||||||
/// </summary>
|
|
||||||
public int MonitoredPropertiesCount => _propertyMetrics.Count;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前监控的集合数量
|
|
||||||
/// </summary>
|
|
||||||
public int MonitoredCollectionsCount => _collectionMetrics.Count;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 构造函数和初始化
|
|
||||||
|
|
||||||
private DataBindingPerformanceMonitor()
|
|
||||||
{
|
|
||||||
_propertyMetrics = new ConcurrentDictionary<string, PropertyUpdateMetrics>();
|
|
||||||
_collectionMetrics = new ConcurrentDictionary<string, CollectionUpdateMetrics>();
|
|
||||||
_updateEvents = new ConcurrentQueue<BindingUpdateEvent>();
|
|
||||||
|
|
||||||
// 定期生成性能报告
|
|
||||||
_reportTimer = new Timer(GeneratePerformanceReport, null, _reportInterval, _reportInterval);
|
|
||||||
|
|
||||||
LogManager.Info("数据绑定性能监控器已初始化");
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 核心监控接口
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 记录属性变更事件的开始
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="viewModelType">ViewModel类型</param>
|
|
||||||
/// <param name="propertyName">属性名称</param>
|
|
||||||
/// <returns>性能测量上下文</returns>
|
|
||||||
public IDisposable BeginPropertyUpdate(Type viewModelType, string propertyName)
|
|
||||||
{
|
|
||||||
if (!_isMonitoringEnabled || _isDisposed)
|
|
||||||
return new EmptyDisposable();
|
|
||||||
|
|
||||||
var key = $"{viewModelType.Name}.{propertyName}";
|
|
||||||
var stopwatch = Stopwatch.StartNew();
|
|
||||||
|
|
||||||
return new PropertyUpdateContext(this, key, stopwatch, Dispatcher.CurrentDispatcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 记录集合变更事件的开始
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="collectionType">集合类型</param>
|
|
||||||
/// <param name="operationType">操作类型(Add, Remove, Clear等)</param>
|
|
||||||
/// <param name="itemCount">影响的项目数量</param>
|
|
||||||
/// <returns>性能测量上下文</returns>
|
|
||||||
public IDisposable BeginCollectionUpdate(Type collectionType, string operationType, int itemCount = 1)
|
|
||||||
{
|
|
||||||
if (!_isMonitoringEnabled || _isDisposed)
|
|
||||||
return new EmptyDisposable();
|
|
||||||
|
|
||||||
var key = $"{collectionType.Name}.{operationType}";
|
|
||||||
var stopwatch = Stopwatch.StartNew();
|
|
||||||
|
|
||||||
return new CollectionUpdateContext(this, key, stopwatch, itemCount, Dispatcher.CurrentDispatcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 记录绑定更新事件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="bindingPath">绑定路径</param>
|
|
||||||
/// <param name="updateType">更新类型</param>
|
|
||||||
/// <param name="durationMs">更新耗时(毫秒)</param>
|
|
||||||
public void RecordBindingUpdate(string bindingPath, string updateType, double durationMs)
|
|
||||||
{
|
|
||||||
if (!_isMonitoringEnabled || _isDisposed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var updateEvent = new BindingUpdateEvent
|
|
||||||
{
|
|
||||||
Timestamp = DateTime.UtcNow,
|
|
||||||
BindingPath = bindingPath,
|
|
||||||
UpdateType = updateType,
|
|
||||||
DurationMs = durationMs,
|
|
||||||
IsSlowUpdate = durationMs > _performanceThresholdMs,
|
|
||||||
ThreadId = Thread.CurrentThread.ManagedThreadId
|
|
||||||
};
|
|
||||||
|
|
||||||
_updateEvents.Enqueue(updateEvent);
|
|
||||||
|
|
||||||
// 限制事件历史记录数量
|
|
||||||
while (_updateEvents.Count > _maxEventHistory)
|
|
||||||
{
|
|
||||||
_updateEvents.TryDequeue(out _);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 记录慢更新警告
|
|
||||||
if (updateEvent.IsSlowUpdate)
|
|
||||||
{
|
|
||||||
LogManager.Warning($"检测到慢数据绑定更新: {bindingPath} ({updateType}) - {durationMs:F2}ms");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 内部方法
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 完成属性更新监控
|
|
||||||
/// </summary>
|
|
||||||
internal void EndPropertyUpdate(string key, Stopwatch stopwatch, Dispatcher dispatcher)
|
|
||||||
{
|
|
||||||
if (_isDisposed) return;
|
|
||||||
|
|
||||||
stopwatch.Stop();
|
|
||||||
var durationMs = stopwatch.Elapsed.TotalMilliseconds;
|
|
||||||
|
|
||||||
var metrics = _propertyMetrics.GetOrAdd(key, _ => new PropertyUpdateMetrics(key));
|
|
||||||
metrics.RecordUpdate(durationMs, dispatcher == Dispatcher.CurrentDispatcher);
|
|
||||||
|
|
||||||
RecordBindingUpdate(key, "PropertyChanged", durationMs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 完成集合更新监控
|
|
||||||
/// </summary>
|
|
||||||
internal void EndCollectionUpdate(string key, Stopwatch stopwatch, int itemCount, Dispatcher dispatcher)
|
|
||||||
{
|
|
||||||
if (_isDisposed) return;
|
|
||||||
|
|
||||||
stopwatch.Stop();
|
|
||||||
var durationMs = stopwatch.Elapsed.TotalMilliseconds;
|
|
||||||
|
|
||||||
var metrics = _collectionMetrics.GetOrAdd(key, _ => new CollectionUpdateMetrics(key));
|
|
||||||
metrics.RecordUpdate(durationMs, itemCount, dispatcher == Dispatcher.CurrentDispatcher);
|
|
||||||
|
|
||||||
RecordBindingUpdate(key, "CollectionChanged", durationMs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 生成性能报告
|
|
||||||
/// </summary>
|
|
||||||
private void GeneratePerformanceReport(object state)
|
|
||||||
{
|
|
||||||
if (_isDisposed) return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var report = GenerateDetailedReport();
|
|
||||||
LogManager.Info($"数据绑定性能报告:\n{report}");
|
|
||||||
|
|
||||||
// 清理过期数据
|
|
||||||
CleanupExpiredData();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogManager.Error($"生成数据绑定性能报告失败: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 清理过期数据
|
|
||||||
/// </summary>
|
|
||||||
private void CleanupExpiredData()
|
|
||||||
{
|
|
||||||
var cutoffTime = DateTime.UtcNow.Subtract(TimeSpan.FromHours(1));
|
|
||||||
|
|
||||||
// 清理属性指标中的过期数据
|
|
||||||
foreach (var metrics in _propertyMetrics.Values)
|
|
||||||
{
|
|
||||||
metrics.CleanupOldData(cutoffTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清理集合指标中的过期数据
|
|
||||||
foreach (var metrics in _collectionMetrics.Values)
|
|
||||||
{
|
|
||||||
metrics.CleanupOldData(cutoffTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 报告生成
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 生成详细的性能报告
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>性能报告字符串</returns>
|
|
||||||
public string GenerateDetailedReport()
|
|
||||||
{
|
|
||||||
var report = new System.Text.StringBuilder();
|
|
||||||
|
|
||||||
report.AppendLine("=== 数据绑定性能监控报告 ===");
|
|
||||||
report.AppendLine($"报告时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
|
|
||||||
report.AppendLine($"监控状态: {(IsMonitoringEnabled ? "启用" : "禁用")}");
|
|
||||||
report.AppendLine($"性能阈值: {PerformanceThresholdMs}ms");
|
|
||||||
report.AppendLine();
|
|
||||||
|
|
||||||
// 属性更新统计
|
|
||||||
report.AppendLine("属性更新性能统计:");
|
|
||||||
var topSlowProperties = _propertyMetrics.Values
|
|
||||||
.Where(m => m.UpdateCount > 0)
|
|
||||||
.OrderByDescending(m => m.AverageUpdateTime)
|
|
||||||
.Take(10)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (topSlowProperties.Any())
|
|
||||||
{
|
|
||||||
foreach (var metrics in topSlowProperties)
|
|
||||||
{
|
|
||||||
report.AppendLine($" {metrics.PropertyKey}:");
|
|
||||||
report.AppendLine($" 更新次数: {metrics.UpdateCount}");
|
|
||||||
report.AppendLine($" 平均耗时: {metrics.AverageUpdateTime:F2}ms");
|
|
||||||
report.AppendLine($" 最大耗时: {metrics.MaxUpdateTime:F2}ms");
|
|
||||||
report.AppendLine($" 慢更新次数: {metrics.SlowUpdateCount}");
|
|
||||||
report.AppendLine($" 跨线程更新次数: {metrics.CrossThreadUpdateCount}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
report.AppendLine(" 暂无属性更新数据");
|
|
||||||
}
|
|
||||||
|
|
||||||
report.AppendLine();
|
|
||||||
|
|
||||||
// 集合更新统计
|
|
||||||
report.AppendLine("集合更新性能统计:");
|
|
||||||
var topSlowCollections = _collectionMetrics.Values
|
|
||||||
.Where(m => m.UpdateCount > 0)
|
|
||||||
.OrderByDescending(m => m.AverageUpdateTime)
|
|
||||||
.Take(10)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (topSlowCollections.Any())
|
|
||||||
{
|
|
||||||
foreach (var metrics in topSlowCollections)
|
|
||||||
{
|
|
||||||
report.AppendLine($" {metrics.CollectionKey}:");
|
|
||||||
report.AppendLine($" 更新次数: {metrics.UpdateCount}");
|
|
||||||
report.AppendLine($" 平均耗时: {metrics.AverageUpdateTime:F2}ms");
|
|
||||||
report.AppendLine($" 最大耗时: {metrics.MaxUpdateTime:F2}ms");
|
|
||||||
report.AppendLine($" 处理项目总数: {metrics.TotalItemsProcessed}");
|
|
||||||
report.AppendLine($" 慢更新次数: {metrics.SlowUpdateCount}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
report.AppendLine(" 暂无集合更新数据");
|
|
||||||
}
|
|
||||||
|
|
||||||
report.AppendLine();
|
|
||||||
|
|
||||||
// 最近的慢更新事件
|
|
||||||
var recentSlowUpdates = _updateEvents
|
|
||||||
.Where(e => e.IsSlowUpdate && e.Timestamp > DateTime.UtcNow.Subtract(TimeSpan.FromMinutes(10)))
|
|
||||||
.OrderByDescending(e => e.DurationMs)
|
|
||||||
.Take(5)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (recentSlowUpdates.Any())
|
|
||||||
{
|
|
||||||
report.AppendLine("最近的慢更新事件 (10分钟内):");
|
|
||||||
foreach (var evt in recentSlowUpdates)
|
|
||||||
{
|
|
||||||
report.AppendLine($" {evt.BindingPath} ({evt.UpdateType}) - {evt.DurationMs:F2}ms @ {evt.Timestamp:HH:mm:ss}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 性能优化建议
|
|
||||||
report.AppendLine();
|
|
||||||
report.AppendLine("性能优化建议:");
|
|
||||||
|
|
||||||
var suggestions = GenerateOptimizationSuggestions();
|
|
||||||
if (suggestions.Any())
|
|
||||||
{
|
|
||||||
foreach (var suggestion in suggestions)
|
|
||||||
{
|
|
||||||
report.AppendLine($" • {suggestion}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
report.AppendLine(" 当前性能表现良好,暂无优化建议");
|
|
||||||
}
|
|
||||||
|
|
||||||
return report.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 生成性能优化建议
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>优化建议列表</returns>
|
|
||||||
public List<string> GenerateOptimizationSuggestions()
|
|
||||||
{
|
|
||||||
var suggestions = new List<string>();
|
|
||||||
|
|
||||||
// 检查频繁更新的属性
|
|
||||||
var frequentProperties = _propertyMetrics.Values
|
|
||||||
.Where(m => m.UpdateCount > 100 && m.AverageUpdateTime > _performanceThresholdMs)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (frequentProperties.Any())
|
|
||||||
{
|
|
||||||
suggestions.Add($"发现{frequentProperties.Count}个高频慢更新属性,建议考虑使用延迟更新或批量更新机制");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查大集合操作
|
|
||||||
var largeCollectionUpdates = _collectionMetrics.Values
|
|
||||||
.Where(m => m.AverageItemsPerUpdate > 1000 && m.AverageUpdateTime > _performanceThresholdMs * 5)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (largeCollectionUpdates.Any())
|
|
||||||
{
|
|
||||||
suggestions.Add($"发现{largeCollectionUpdates.Count}个大集合更新操作,建议实现虚拟化或分页机制");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查跨线程更新
|
|
||||||
var crossThreadUpdates = _propertyMetrics.Values
|
|
||||||
.Where(m => m.CrossThreadUpdateCount > m.UpdateCount * 0.1) // 超过10%的跨线程更新
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (crossThreadUpdates.Any())
|
|
||||||
{
|
|
||||||
suggestions.Add($"发现{crossThreadUpdates.Count}个属性存在频繁的跨线程更新,建议优化线程调度");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查内存使用
|
|
||||||
var totalMetrics = _propertyMetrics.Count + _collectionMetrics.Count;
|
|
||||||
if (totalMetrics > 1000)
|
|
||||||
{
|
|
||||||
suggestions.Add("监控的绑定数量较多,建议定期清理不再使用的绑定以释放内存");
|
|
||||||
}
|
|
||||||
|
|
||||||
return suggestions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取性能概览数据
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>性能概览</returns>
|
|
||||||
public PerformanceOverview GetPerformanceOverview()
|
|
||||||
{
|
|
||||||
var totalPropertyUpdates = _propertyMetrics.Values.Sum(m => m.UpdateCount);
|
|
||||||
var totalCollectionUpdates = _collectionMetrics.Values.Sum(m => m.UpdateCount);
|
|
||||||
var totalSlowUpdates = _updateEvents.Count(e => e.IsSlowUpdate);
|
|
||||||
|
|
||||||
var avgPropertyUpdateTime = _propertyMetrics.Values
|
|
||||||
.Where(m => m.UpdateCount > 0)
|
|
||||||
.DefaultIfEmpty(new PropertyUpdateMetrics("dummy"))
|
|
||||||
.Average(m => m.AverageUpdateTime);
|
|
||||||
|
|
||||||
var avgCollectionUpdateTime = _collectionMetrics.Values
|
|
||||||
.Where(m => m.UpdateCount > 0)
|
|
||||||
.DefaultIfEmpty(new CollectionUpdateMetrics("dummy"))
|
|
||||||
.Average(m => m.AverageUpdateTime);
|
|
||||||
|
|
||||||
return new PerformanceOverview
|
|
||||||
{
|
|
||||||
TotalPropertyUpdates = totalPropertyUpdates,
|
|
||||||
TotalCollectionUpdates = totalCollectionUpdates,
|
|
||||||
TotalSlowUpdates = totalSlowUpdates,
|
|
||||||
AveragePropertyUpdateTime = avgPropertyUpdateTime,
|
|
||||||
AverageCollectionUpdateTime = avgCollectionUpdateTime,
|
|
||||||
MonitoredPropertiesCount = MonitoredPropertiesCount,
|
|
||||||
MonitoredCollectionsCount = MonitoredCollectionsCount,
|
|
||||||
IsHealthy = totalSlowUpdates < (totalPropertyUpdates + totalCollectionUpdates) * 0.05 // 少于5%的慢更新
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 配置管理
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置监控配置
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="reportInterval">报告生成间隔</param>
|
|
||||||
/// <param name="maxEventHistory">最大事件历史记录数</param>
|
|
||||||
/// <param name="performanceThreshold">性能阈值(毫秒)</param>
|
|
||||||
public void ConfigureMonitoring(TimeSpan reportInterval, int maxEventHistory, int performanceThreshold)
|
|
||||||
{
|
|
||||||
_reportInterval = reportInterval;
|
|
||||||
_maxEventHistory = Math.Max(100, maxEventHistory);
|
|
||||||
_performanceThresholdMs = Math.Max(1, performanceThreshold);
|
|
||||||
|
|
||||||
// 重启定时器
|
|
||||||
_reportTimer?.Change(_reportInterval, _reportInterval);
|
|
||||||
|
|
||||||
LogManager.Info($"数据绑定监控配置已更新 - 报告间隔: {reportInterval}, 事件历史: {maxEventHistory}, 性能阈值: {performanceThreshold}ms");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 重置所有监控数据
|
|
||||||
/// </summary>
|
|
||||||
public void ResetMonitoringData()
|
|
||||||
{
|
|
||||||
_propertyMetrics.Clear();
|
|
||||||
_collectionMetrics.Clear();
|
|
||||||
|
|
||||||
while (_updateEvents.TryDequeue(out _)) { }
|
|
||||||
|
|
||||||
LogManager.Info("数据绑定监控数据已重置");
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region IDisposable实现
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (_isDisposed) return;
|
|
||||||
|
|
||||||
_isDisposed = true;
|
|
||||||
_isMonitoringEnabled = false;
|
|
||||||
|
|
||||||
_reportTimer?.Dispose();
|
|
||||||
|
|
||||||
// 生成最终报告
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var finalReport = GenerateDetailedReport();
|
|
||||||
LogManager.Info($"数据绑定性能监控最终报告:\n{finalReport}");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogManager.Error($"生成最终性能报告失败: {ex.Message}");
|
|
||||||
}
|
|
||||||
|
|
||||||
_propertyMetrics.Clear();
|
|
||||||
_collectionMetrics.Clear();
|
|
||||||
|
|
||||||
LogManager.Info("数据绑定性能监控器已释放");
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
#region 辅助类和数据结构
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 属性更新上下文 - 用于测量属性更新性能
|
|
||||||
/// </summary>
|
|
||||||
internal class PropertyUpdateContext : IDisposable
|
|
||||||
{
|
|
||||||
private readonly DataBindingPerformanceMonitor _monitor;
|
|
||||||
private readonly string _key;
|
|
||||||
private readonly Stopwatch _stopwatch;
|
|
||||||
private readonly Dispatcher _dispatcher;
|
|
||||||
|
|
||||||
public PropertyUpdateContext(DataBindingPerformanceMonitor monitor, string key, Stopwatch stopwatch, Dispatcher dispatcher)
|
|
||||||
{
|
|
||||||
_monitor = monitor;
|
|
||||||
_key = key;
|
|
||||||
_stopwatch = stopwatch;
|
|
||||||
_dispatcher = dispatcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_monitor.EndPropertyUpdate(_key, _stopwatch, _dispatcher);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 集合更新上下文 - 用于测量集合更新性能
|
|
||||||
/// </summary>
|
|
||||||
internal class CollectionUpdateContext : IDisposable
|
|
||||||
{
|
|
||||||
private readonly DataBindingPerformanceMonitor _monitor;
|
|
||||||
private readonly string _key;
|
|
||||||
private readonly Stopwatch _stopwatch;
|
|
||||||
private readonly int _itemCount;
|
|
||||||
private readonly Dispatcher _dispatcher;
|
|
||||||
|
|
||||||
public CollectionUpdateContext(DataBindingPerformanceMonitor monitor, string key, Stopwatch stopwatch, int itemCount, Dispatcher dispatcher)
|
|
||||||
{
|
|
||||||
_monitor = monitor;
|
|
||||||
_key = key;
|
|
||||||
_stopwatch = stopwatch;
|
|
||||||
_itemCount = itemCount;
|
|
||||||
_dispatcher = dispatcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_monitor.EndCollectionUpdate(_key, _stopwatch, _itemCount, _dispatcher);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 空的IDisposable实现 - 用于禁用监控时的占位符
|
|
||||||
/// </summary>
|
|
||||||
internal class EmptyDisposable : IDisposable
|
|
||||||
{
|
|
||||||
public void Dispose() { }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 属性更新性能指标
|
|
||||||
/// </summary>
|
|
||||||
public class PropertyUpdateMetrics
|
|
||||||
{
|
|
||||||
public string PropertyKey { get; }
|
|
||||||
public long UpdateCount { get; private set; }
|
|
||||||
public double TotalUpdateTime { get; private set; }
|
|
||||||
public double MaxUpdateTime { get; private set; }
|
|
||||||
public long SlowUpdateCount { get; private set; }
|
|
||||||
public long CrossThreadUpdateCount { get; private set; }
|
|
||||||
public DateTime LastUpdateTime { get; private set; }
|
|
||||||
|
|
||||||
public double AverageUpdateTime => UpdateCount > 0 ? TotalUpdateTime / UpdateCount : 0;
|
|
||||||
|
|
||||||
private readonly List<DateTime> _updateTimes = new List<DateTime>();
|
|
||||||
|
|
||||||
public PropertyUpdateMetrics(string propertyKey)
|
|
||||||
{
|
|
||||||
PropertyKey = propertyKey;
|
|
||||||
LastUpdateTime = DateTime.UtcNow;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RecordUpdate(double durationMs, bool isOnUIThread)
|
|
||||||
{
|
|
||||||
UpdateCount++;
|
|
||||||
TotalUpdateTime += durationMs;
|
|
||||||
MaxUpdateTime = Math.Max(MaxUpdateTime, durationMs);
|
|
||||||
LastUpdateTime = DateTime.UtcNow;
|
|
||||||
|
|
||||||
if (durationMs > 16) // 60FPS阈值
|
|
||||||
{
|
|
||||||
SlowUpdateCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isOnUIThread)
|
|
||||||
{
|
|
||||||
CrossThreadUpdateCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
_updateTimes.Add(DateTime.UtcNow);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CleanupOldData(DateTime cutoffTime)
|
|
||||||
{
|
|
||||||
_updateTimes.RemoveAll(t => t < cutoffTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 集合更新性能指标
|
|
||||||
/// </summary>
|
|
||||||
public class CollectionUpdateMetrics
|
|
||||||
{
|
|
||||||
public string CollectionKey { get; }
|
|
||||||
public long UpdateCount { get; private set; }
|
|
||||||
public double TotalUpdateTime { get; private set; }
|
|
||||||
public double MaxUpdateTime { get; private set; }
|
|
||||||
public long TotalItemsProcessed { get; private set; }
|
|
||||||
public long SlowUpdateCount { get; private set; }
|
|
||||||
public DateTime LastUpdateTime { get; private set; }
|
|
||||||
|
|
||||||
public double AverageUpdateTime => UpdateCount > 0 ? TotalUpdateTime / UpdateCount : 0;
|
|
||||||
public double AverageItemsPerUpdate => UpdateCount > 0 ? (double)TotalItemsProcessed / UpdateCount : 0;
|
|
||||||
|
|
||||||
private readonly List<DateTime> _updateTimes = new List<DateTime>();
|
|
||||||
|
|
||||||
public CollectionUpdateMetrics(string collectionKey)
|
|
||||||
{
|
|
||||||
CollectionKey = collectionKey;
|
|
||||||
LastUpdateTime = DateTime.UtcNow;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RecordUpdate(double durationMs, int itemCount, bool isOnUIThread)
|
|
||||||
{
|
|
||||||
UpdateCount++;
|
|
||||||
TotalUpdateTime += durationMs;
|
|
||||||
MaxUpdateTime = Math.Max(MaxUpdateTime, durationMs);
|
|
||||||
TotalItemsProcessed += itemCount;
|
|
||||||
LastUpdateTime = DateTime.UtcNow;
|
|
||||||
|
|
||||||
if (durationMs > 50) // 集合操作的更宽松阈值
|
|
||||||
{
|
|
||||||
SlowUpdateCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
_updateTimes.Add(DateTime.UtcNow);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CleanupOldData(DateTime cutoffTime)
|
|
||||||
{
|
|
||||||
_updateTimes.RemoveAll(t => t < cutoffTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 绑定更新事件
|
|
||||||
/// </summary>
|
|
||||||
public class BindingUpdateEvent
|
|
||||||
{
|
|
||||||
public DateTime Timestamp { get; set; }
|
|
||||||
public string BindingPath { get; set; }
|
|
||||||
public string UpdateType { get; set; }
|
|
||||||
public double DurationMs { get; set; }
|
|
||||||
public bool IsSlowUpdate { get; set; }
|
|
||||||
public int ThreadId { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 性能概览数据
|
|
||||||
/// </summary>
|
|
||||||
public class PerformanceOverview
|
|
||||||
{
|
|
||||||
public long TotalPropertyUpdates { get; set; }
|
|
||||||
public long TotalCollectionUpdates { get; set; }
|
|
||||||
public long TotalSlowUpdates { get; set; }
|
|
||||||
public double AveragePropertyUpdateTime { get; set; }
|
|
||||||
public double AverageCollectionUpdateTime { get; set; }
|
|
||||||
public int MonitoredPropertiesCount { get; set; }
|
|
||||||
public int MonitoredCollectionsCount { get; set; }
|
|
||||||
public bool IsHealthy { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
@ -35,9 +35,6 @@ namespace NavisworksTransport.UI.WPF.Services
|
|||||||
private readonly Dictionary<string, ConditionalUpdateConfig> _conditionalConfigs;
|
private readonly Dictionary<string, ConditionalUpdateConfig> _conditionalConfigs;
|
||||||
private readonly object _conditionalConfigLock = new object();
|
private readonly object _conditionalConfigLock = new object();
|
||||||
|
|
||||||
// 性能监控集成
|
|
||||||
private readonly DataBindingPerformanceMonitor _performanceMonitor;
|
|
||||||
|
|
||||||
// 配置选项
|
// 配置选项
|
||||||
private TimeSpan _defaultDelayInterval = TimeSpan.FromMilliseconds(100);
|
private TimeSpan _defaultDelayInterval = TimeSpan.FromMilliseconds(100);
|
||||||
private TimeSpan _batchUpdateInterval = TimeSpan.FromMilliseconds(50);
|
private TimeSpan _batchUpdateInterval = TimeSpan.FromMilliseconds(50);
|
||||||
@ -102,8 +99,6 @@ namespace NavisworksTransport.UI.WPF.Services
|
|||||||
_batchUpdates = new Dictionary<object, BatchUpdateContext>();
|
_batchUpdates = new Dictionary<object, BatchUpdateContext>();
|
||||||
_conditionalConfigs = new Dictionary<string, ConditionalUpdateConfig>();
|
_conditionalConfigs = new Dictionary<string, ConditionalUpdateConfig>();
|
||||||
|
|
||||||
_performanceMonitor = DataBindingPerformanceMonitor.Instance;
|
|
||||||
|
|
||||||
// 初始化延迟更新定时器
|
// 初始化延迟更新定时器
|
||||||
_delayedUpdateTimer = new Timer(ProcessDelayedUpdates, null, _defaultDelayInterval, _defaultDelayInterval);
|
_delayedUpdateTimer = new Timer(ProcessDelayedUpdates, null, _defaultDelayInterval, _defaultDelayInterval);
|
||||||
|
|
||||||
@ -241,10 +236,7 @@ namespace NavisworksTransport.UI.WPF.Services
|
|||||||
if (target == null)
|
if (target == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using (_performanceMonitor.BeginPropertyUpdate(target.GetType(), context.PropertyName))
|
context.UpdateAction?.Invoke();
|
||||||
{
|
|
||||||
context.UpdateAction?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
LogManager.Debug($"执行延迟更新: {context.PropertyName}, 合并次数: {context.UpdateCount}");
|
LogManager.Debug($"执行延迟更新: {context.PropertyName}, 合并次数: {context.UpdateCount}");
|
||||||
}
|
}
|
||||||
@ -436,22 +428,19 @@ namespace NavisworksTransport.UI.WPF.Services
|
|||||||
{
|
{
|
||||||
var duration = DateTime.UtcNow - context.StartTime;
|
var duration = DateTime.UtcNow - context.StartTime;
|
||||||
|
|
||||||
using (_performanceMonitor.BeginPropertyUpdate(target.GetType(), $"BatchUpdate_{properties.Count}Properties"))
|
// 如果目标实现了批量更新接口,使用其批量方法
|
||||||
|
if (target is ViewModelBase viewModelBase)
|
||||||
{
|
{
|
||||||
// 如果目标实现了批量更新接口,使用其批量方法
|
viewModelBase.OnPropertiesChanged(properties.ToArray());
|
||||||
if (target is ViewModelBase viewModelBase)
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 否则逐个触发属性变更通知
|
||||||
|
foreach (var propertyName in properties)
|
||||||
{
|
{
|
||||||
viewModelBase.OnPropertiesChanged(properties.ToArray());
|
// 使用反射或其他方式触发PropertyChanged事件
|
||||||
}
|
// 这里需要根据具体的INotifyPropertyChanged实现来调用
|
||||||
else
|
TriggerPropertyChanged(target, propertyName);
|
||||||
{
|
|
||||||
// 否则逐个触发属性变更通知
|
|
||||||
foreach (var propertyName in properties)
|
|
||||||
{
|
|
||||||
// 使用反射或其他方式触发PropertyChanged事件
|
|
||||||
// 这里需要根据具体的INotifyPropertyChanged实现来调用
|
|
||||||
TriggerPropertyChanged(target, propertyName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -606,10 +595,7 @@ namespace NavisworksTransport.UI.WPF.Services
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 执行延迟的更新
|
// 执行延迟的更新
|
||||||
using (_performanceMonitor.BeginPropertyUpdate(target.GetType(), propertyName))
|
TriggerPropertyChanged(target, propertyName);
|
||||||
{
|
|
||||||
TriggerPropertyChanged(target, propertyName);
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (_conditionalConfigLock)
|
lock (_conditionalConfigLock)
|
||||||
{
|
{
|
||||||
@ -680,16 +666,6 @@ namespace NavisworksTransport.UI.WPF.Services
|
|||||||
|
|
||||||
report.AppendLine("条件更新机制:");
|
report.AppendLine("条件更新机制:");
|
||||||
report.AppendLine($" 配置的条件更新: {stats.ConfiguredConditionalUpdates}");
|
report.AppendLine($" 配置的条件更新: {stats.ConfiguredConditionalUpdates}");
|
||||||
report.AppendLine();
|
|
||||||
|
|
||||||
// 集成性能监控数据
|
|
||||||
var performanceOverview = _performanceMonitor.GetPerformanceOverview();
|
|
||||||
report.AppendLine("性能概览:");
|
|
||||||
report.AppendLine($" 总属性更新: {performanceOverview.TotalPropertyUpdates}");
|
|
||||||
report.AppendLine($" 总集合更新: {performanceOverview.TotalCollectionUpdates}");
|
|
||||||
report.AppendLine($" 慢更新次数: {performanceOverview.TotalSlowUpdates}");
|
|
||||||
report.AppendLine($" 平均属性更新时间: {performanceOverview.AveragePropertyUpdateTime:F2}ms");
|
|
||||||
report.AppendLine($" 系统健康状态: {(performanceOverview.IsHealthy ? "良好" : "需要优化")}");
|
|
||||||
|
|
||||||
return report.ToString();
|
return report.ToString();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,11 +32,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly SmartDataBindingOptimizer _bindingOptimizer;
|
private readonly SmartDataBindingOptimizer _bindingOptimizer;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 数据绑定性能监控器,监控绑定性能
|
|
||||||
/// </summary>
|
|
||||||
private readonly DataBindingPerformanceMonitor _performanceMonitor;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 正在更新的属性集合,用于防重入检测
|
/// 正在更新的属性集合,用于防重入检测
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -52,11 +47,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected bool IsSmartOptimizationEnabled { get; set; } = true;
|
protected bool IsSmartOptimizationEnabled { get; set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否启用性能监控
|
|
||||||
/// </summary>
|
|
||||||
protected bool IsPerformanceMonitoringEnabled { get; set; } = true;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 主ViewModel引用,用于统一状态栏更新
|
/// 主ViewModel引用,用于统一状态栏更新
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -73,7 +63,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
{
|
{
|
||||||
_uiStateManager = UIStateManager.Instance;
|
_uiStateManager = UIStateManager.Instance;
|
||||||
_bindingOptimizer = SmartDataBindingOptimizer.Instance;
|
_bindingOptimizer = SmartDataBindingOptimizer.Instance;
|
||||||
_performanceMonitor = DataBindingPerformanceMonitor.Instance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -81,7 +70,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
#region 属性更新方法
|
#region 属性更新方法
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 触发属性变更通知(线程安全,防重入,集成性能监控)
|
/// 触发属性变更通知(线程安全,防重入)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="propertyName">属性名称,自动获取调用者名称</param>
|
/// <param name="propertyName">属性名称,自动获取调用者名称</param>
|
||||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||||
@ -91,13 +80,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 性能监控
|
|
||||||
IDisposable performanceContext = null;
|
|
||||||
if (IsPerformanceMonitoringEnabled)
|
|
||||||
{
|
|
||||||
performanceContext = _performanceMonitor.BeginPropertyUpdate(this.GetType(), propertyName);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 防重入检查
|
// 防重入检查
|
||||||
@ -109,7 +91,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
LogManager.Debug($"[ViewModel] 检测到属性重入更新,跳过: {propertyName}");
|
LogManager.Debug($"[ViewModel] 检测到属性重入更新,跳过: {propertyName}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 标记属性为正在更新状态
|
// 标记属性为正在更新状态
|
||||||
_updatingProperties.Add(propertyName);
|
_updatingProperties.Add(propertyName);
|
||||||
}
|
}
|
||||||
@ -140,9 +122,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
{
|
{
|
||||||
_updatingProperties.Remove(propertyName);
|
_updatingProperties.Remove(propertyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 结束性能监控
|
|
||||||
performanceContext?.Dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,37 +489,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 性能监控和诊断
|
#region 诊断方法
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前ViewModel的绑定性能统计
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>性能统计信息</returns>
|
|
||||||
protected virtual string GetBindingPerformanceReport()
|
|
||||||
{
|
|
||||||
if (!IsPerformanceMonitoringEnabled)
|
|
||||||
return "性能监控已禁用";
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return _performanceMonitor.GenerateDetailedReport();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogManager.Error($"[ViewModel] 生成性能报告失败: {ex.Message}");
|
|
||||||
return $"生成性能报告失败: {ex.Message}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 启用或禁用性能监控
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="enabled">是否启用</param>
|
|
||||||
protected void SetPerformanceMonitoring(bool enabled)
|
|
||||||
{
|
|
||||||
IsPerformanceMonitoringEnabled = enabled;
|
|
||||||
_performanceMonitor.IsMonitoringEnabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 启用或禁用智能优化
|
/// 启用或禁用智能优化
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user