NavisworksTransport/src/UI/WPF/ViewModels/ViewModelBase.cs
2025-10-21 18:48:27 +08:00

740 lines
26 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.ComponentModel;
using System.Runtime.CompilerServices;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NavisworksTransport.Core;
using NavisworksTransport.UI.WPF.Services;
using NavisworksTransport.UI.WPF.Interfaces;
namespace NavisworksTransport.UI.WPF.ViewModels
{
/// <summary>
/// ViewModel基类实现INotifyPropertyChanged接口
/// 集成UIStateManager提供线程安全的属性更新和防重入机制
/// 集成智能数据绑定优化功能,支持延迟更新、批量更新和条件更新
/// </summary>
public abstract class ViewModelBase : IPropertyChangeNotifier
{
#region
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// UI状态管理器提供线程安全的UI更新机制
/// </summary>
private readonly UIStateManager _uiStateManager;
/// <summary>
/// 智能数据绑定优化器,提供延迟更新、批量更新等优化功能
/// </summary>
private readonly SmartDataBindingOptimizer _bindingOptimizer;
/// <summary>
/// 正在更新的属性集合,用于防重入检测
/// </summary>
private readonly HashSet<string> _updatingProperties = new HashSet<string>();
/// <summary>
/// 属性更新锁,确保线程安全
/// </summary>
private readonly object _propertyLock = new object();
/// <summary>
/// 是否启用智能优化功能
/// </summary>
protected bool IsSmartOptimizationEnabled { get; set; } = true;
/// <summary>
/// 主ViewModel引用用于统一状态栏更新
/// </summary>
protected LogisticsControlViewModel _mainViewModel;
#endregion
#region
/// <summary>
/// 初始化ViewModelBase
/// </summary>
protected ViewModelBase()
{
_uiStateManager = UIStateManager.Instance;
_bindingOptimizer = SmartDataBindingOptimizer.Instance;
}
#endregion
#region
/// <summary>
/// 触发属性变更通知(线程安全,防重入)
/// </summary>
/// <param name="propertyName">属性名称,自动获取调用者名称</param>
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (string.IsNullOrEmpty(propertyName))
{
return;
}
try
{
// 防重入检查
lock (_propertyLock)
{
if (_updatingProperties.Contains(propertyName))
{
// 属性正在更新中,防止重入
LogManager.Debug($"[ViewModel] 检测到属性重入更新,跳过: {propertyName}");
return;
}
// 标记属性为正在更新状态
_updatingProperties.Add(propertyName);
}
// 使用UIStateManager确保在UI线程上安全执行
if (_uiStateManager.IsUIThread)
{
// 已在UI线程上直接触发
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
else
{
// 异步切换到UI线程执行
_ = _uiStateManager.ExecuteUIUpdateAsync(() =>
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
});
}
}
catch (Exception ex)
{
LogManager.Error($"[ViewModel] OnPropertyChanged失败: {ex.Message},属性: {propertyName}");
}
finally
{
// 清除更新标记
lock (_propertyLock)
{
_updatingProperties.Remove(propertyName);
}
}
}
/// <summary>
/// 公共接口:触发指定属性的变更通知(供外部组件使用,替代反射调用)
/// </summary>
/// <param name="propertyName">属性名称</param>
public virtual void NotifyPropertyChanged(string propertyName)
{
OnPropertyChanged(propertyName);
}
/// <summary>
/// 同步触发属性变更通知确保在UI线程上执行完成
/// </summary>
/// <param name="propertyName">属性名称</param>
/// <param name="timeout">超时时间毫秒默认3000ms</param>
protected virtual async Task OnPropertyChangedAsync(string propertyName, int timeout = 3000)
{
if (string.IsNullOrEmpty(propertyName))
{
return;
}
// 防重入检查
lock (_propertyLock)
{
if (_updatingProperties.Contains(propertyName))
{
LogManager.Debug($"[ViewModel] 检测到属性重入更新,跳过: {propertyName}");
return;
}
_updatingProperties.Add(propertyName);
}
try
{
// 使用UIStateManager确保同步执行
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}, timeout);
}
catch (Exception ex)
{
LogManager.Error($"[ViewModel] OnPropertyChangedAsync失败: {ex.Message},属性: {propertyName}");
throw;
}
finally
{
lock (_propertyLock)
{
_updatingProperties.Remove(propertyName);
}
}
}
/// <summary>
/// 批量触发属性变更通知(原子性操作)
/// </summary>
/// <param name="propertyNames">要更新的属性名称数组</param>
public virtual void OnPropertiesChanged(params string[] propertyNames)
{
if (propertyNames == null || propertyNames.Length == 0)
{
return;
}
// 去重并过滤空值
var uniqueProperties = propertyNames.Where(p => !string.IsNullOrEmpty(p)).Distinct().ToArray();
if (uniqueProperties.Length == 0)
{
return;
}
// 防重入检查
var propertiesToUpdate = new List<string>();
lock (_propertyLock)
{
foreach (var propertyName in uniqueProperties)
{
if (!_updatingProperties.Contains(propertyName))
{
_updatingProperties.Add(propertyName);
propertiesToUpdate.Add(propertyName);
}
else
{
LogManager.Debug($"[ViewModel] 检测到属性重入更新,跳过: {propertyName}");
}
}
}
if (propertiesToUpdate.Count == 0)
{
return; // 所有属性都在更新中,避免重入
}
try
{
// 创建批量更新操作
var updateActions = propertiesToUpdate.Select(propertyName =>
new Action(() => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)))
).ToArray();
// 使用UIStateManager批量执行
_ = _uiStateManager.ExecuteBatchUIUpdate(updateActions);
}
catch (Exception ex)
{
LogManager.Error($"[ViewModel] OnPropertiesChanged失败: {ex.Message},属性: {string.Join(", ", propertiesToUpdate)}");
}
finally
{
// 清除所有更新标记
lock (_propertyLock)
{
foreach (var propertyName in propertiesToUpdate)
{
_updatingProperties.Remove(propertyName);
}
}
}
}
/// <summary>
/// 批量设置属性值并触发变更通知(原子性操作)
/// </summary>
/// <param name="properties">属性名称和值的键值对数组</param>
protected virtual void SetProperties(params (string name, object value)[] properties)
{
if (properties == null || properties.Length == 0)
{
return;
}
try
{
// 批量更新操作
var updateActions = properties.Select(p =>
new Action(() => OnPropertyChanged(p.name))
).ToArray();
// 使用UIStateManager批量执行
_ = _uiStateManager.ExecuteBatchUIUpdate(updateActions);
}
catch (Exception ex)
{
LogManager.Error($"[ViewModel] SetProperties失败: {ex.Message}");
}
}
#endregion
#region
/// <summary>
/// 设置属性值并触发变更通知(线程安全)
/// </summary>
/// <typeparam name="T">属性类型</typeparam>
/// <param name="field">字段引用</param>
/// <param name="value">新值</param>
/// <param name="propertyName">属性名称,自动获取调用者名称</param>
/// <returns>如果值发生变化返回true</returns>
protected bool SetProperty<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;
}
/// <summary>
/// 异步设置属性值并触发变更通知确保UI线程同步执行
/// </summary>
/// <typeparam name="T">属性类型</typeparam>
/// <param name="field">字段引用</param>
/// <param name="value">新值</param>
/// <param name="propertyName">属性名称,自动获取调用者名称</param>
/// <param name="timeout">超时时间毫秒默认3000ms</param>
/// <returns>如果值发生变化返回true</returns>
protected async Task<bool> SetPropertyAsync<T>(T field, T value, [CallerMemberName] string propertyName = null, int timeout = 3000)
{
if (EqualityComparer<T>.Default.Equals(field, value))
return false;
await OnPropertyChangedAsync(propertyName, timeout);
return true;
}
/// <summary>
/// 线程安全的属性设置方法使用UIStateManager确保线程安全
/// </summary>
/// <typeparam name="T">属性类型</typeparam>
/// <param name="field">字段引用</param>
/// <param name="value">新值</param>
/// <param name="propertyName">属性名称,自动获取调用者名称</param>
/// <returns>如果值发生变化返回true</returns>
protected bool SetPropertyThreadSafe<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value))
return false;
field = value;
// 使用UIStateManager确保在UI线程上触发属性变更通知
if (_uiStateManager.IsUIThread)
{
OnPropertyChanged(propertyName);
}
else
{
_ = _uiStateManager.ExecuteUIUpdateAsync(() => OnPropertyChanged(propertyName));
}
return true;
}
#endregion
#region
/// <summary>
/// 延迟触发属性变更通知 - 将快速连续的更新合并为一次通知
/// </summary>
/// <param name="propertyName">属性名称</param>
/// <param name="delayInterval">延迟间隔null使用默认值</param>
protected void OnPropertyChangedDelayed([CallerMemberName] string propertyName = null, TimeSpan? delayInterval = null)
{
if (!IsSmartOptimizationEnabled || string.IsNullOrEmpty(propertyName))
{
OnPropertyChanged(propertyName);
return;
}
_bindingOptimizer.RegisterDelayedUpdate(this, propertyName, () => OnPropertyChanged(propertyName), delayInterval);
}
/// <summary>
/// 条件性触发属性变更通知 - 只有满足条件时才触发更新
/// </summary>
/// <typeparam name="T">属性类型</typeparam>
/// <param name="field">字段引用</param>
/// <param name="value">新值</param>
/// <param name="condition">更新条件</param>
/// <param name="propertyName">属性名称</param>
/// <returns>是否触发了更新</returns>
protected bool SetPropertyConditional<T>(ref T field, T value, Func<T, T, bool> condition, [CallerMemberName] string propertyName = null)
{
if (condition != null && !condition(field, value))
return false;
return SetProperty(ref field, value, propertyName);
}
/// <summary>
/// 设置属性值并支持智能优化
/// </summary>
/// <typeparam name="T">属性类型</typeparam>
/// <param name="field">字段引用</param>
/// <param name="value">新值</param>
/// <param name="updateMode">更新模式</param>
/// <param name="propertyName">属性名称</param>
/// <returns>是否发生了变化</returns>
public bool SetPropertySmart<T>(ref T field, T value, PropertyUpdateMode updateMode = PropertyUpdateMode.Immediate, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value))
return false;
var oldValue = field;
field = value;
switch (updateMode)
{
case PropertyUpdateMode.Immediate:
OnPropertyChanged(propertyName);
break;
case PropertyUpdateMode.Delayed:
OnPropertyChangedDelayed(propertyName);
break;
case PropertyUpdateMode.Conditional:
if (IsSmartOptimizationEnabled)
{
if (_bindingOptimizer.ShouldUpdateProperty(this, propertyName, oldValue, value))
{
OnPropertyChanged(propertyName);
}
}
else
{
OnPropertyChanged(propertyName);
}
break;
}
return true;
}
/// <summary>
/// 开始批量属性更新 - 在作用域内的所有属性更新将被合并
/// </summary>
/// <returns>批量更新作用域</returns>
public IBatchUpdateScope BeginBatchUpdate()
{
if (!IsSmartOptimizationEnabled)
return new EmptyBatchScope();
return _bindingOptimizer.BeginBatchUpdate(this);
}
/// <summary>
/// 配置属性的条件更新规则
/// </summary>
/// <param name="propertyName">属性名称</param>
/// <param name="condition">更新条件</param>
/// <param name="config">条件配置</param>
public void ConfigurePropertyUpdate(string propertyName, Func<object, object, bool> condition, ConditionalUpdateConfig config = null)
{
if (!IsSmartOptimizationEnabled || string.IsNullOrEmpty(propertyName))
return;
_bindingOptimizer.ConfigureConditionalUpdate(this, propertyName, condition, config);
}
/// <summary>
/// 立即刷新所有延迟的属性更新
/// </summary>
protected void FlushDelayedUpdates()
{
if (IsSmartOptimizationEnabled)
{
_bindingOptimizer.FlushDelayedUpdates(this);
}
}
/// <summary>
/// 批量设置多个属性(在单个批量更新作用域内)
/// </summary>
/// <param name="propertyUpdates">属性更新操作集合</param>
protected void SetPropertiesBatch(params Action[] propertyUpdates)
{
if (propertyUpdates == null || propertyUpdates.Length == 0)
return;
using (BeginBatchUpdate())
{
foreach (var update in propertyUpdates)
{
try
{
update?.Invoke();
}
catch (Exception ex)
{
LogManager.Error($"[ViewModel] 批量属性更新失败: {ex.Message}");
}
}
}
}
#endregion
#region
/// <summary>
/// 启用或禁用智能优化
/// </summary>
/// <param name="enabled">是否启用</param>
protected void SetSmartOptimization(bool enabled)
{
IsSmartOptimizationEnabled = enabled;
}
/// <summary>
/// 获取智能优化器的统计信息
/// </summary>
/// <returns>优化器统计</returns>
protected OptimizerStatistics GetOptimizerStatistics()
{
return _bindingOptimizer.GetStatistics();
}
#endregion
#region
/// <summary>
/// 安全执行操作捕获异常使用UIStateManager确保线程安全
/// </summary>
/// <param name="action">要执行的操作</param>
/// <param name="operationName">操作名称</param>
/// <param name="runOnUIThread">是否强制在UI线程上执行</param>
protected void SafeExecute(Action action, string operationName = "操作", bool runOnUIThread = false)
{
if (action == null)
{
LogManager.Warning($"[ViewModel] SafeExecute接收到空操作: {operationName}");
return;
}
try
{
if (runOnUIThread && !_uiStateManager.IsUIThread)
{
// 异步切换到UI线程执行
_ = _uiStateManager.ExecuteUIUpdateAsync(action);
}
else
{
// 直接执行
action();
}
}
catch (Exception ex)
{
LogManager.Error($"[ViewModel] {operationName}失败: {ex.Message}");
LogManager.Error($"[ViewModel] 堆栈信息: {ex.StackTrace}");
}
}
/// <summary>
/// 安全执行操作捕获异常并返回结果使用UIStateManager确保线程安全
/// </summary>
/// <typeparam name="T">返回类型</typeparam>
/// <param name="func">要执行的函数</param>
/// <param name="defaultValue">默认返回值</param>
/// <param name="operationName">操作名称</param>
/// <param name="runOnUIThread">是否强制在UI线程上执行</param>
/// <returns>执行结果或默认值</returns>
protected T SafeExecute<T>(Func<T> func, T defaultValue = default(T), string operationName = "操作", bool runOnUIThread = false)
{
if (func == null)
{
LogManager.Warning($"[ViewModel] SafeExecute接收到空函数: {operationName}");
return defaultValue;
}
try
{
if (runOnUIThread && !_uiStateManager.IsUIThread)
{
// 同步切换到UI线程执行
return _uiStateManager.ExecuteUIUpdateAsync(func).Result;
}
else
{
// 直接执行
return func();
}
}
catch (Exception ex)
{
LogManager.Error($"[ViewModel] {operationName}失败: {ex.Message}");
LogManager.Error($"[ViewModel] 堆栈信息: {ex.StackTrace}");
return defaultValue;
}
}
/// <summary>
/// 异步安全执行操作捕获异常确保在UI线程上执行
/// </summary>
/// <param name="action">要执行的操作</param>
/// <param name="operationName">操作名称</param>
/// <param name="timeout">超时时间毫秒默认5000ms</param>
protected async Task SafeExecuteAsync(Action action, string operationName = "操作", int timeout = 5000)
{
if (action == null)
{
LogManager.Warning($"[ViewModel] SafeExecuteAsync接收到空操作: {operationName}");
return;
}
try
{
await _uiStateManager.ExecuteUIUpdateAsync(action, timeout);
}
catch (Exception ex)
{
LogManager.Error($"[ViewModel] {operationName}异步执行失败: {ex.Message}");
LogManager.Error($"[ViewModel] 堆栈信息: {ex.StackTrace}");
}
}
/// <summary>
/// 异步安全执行操作捕获异常并返回结果确保在UI线程上执行
/// </summary>
/// <typeparam name="T">返回类型</typeparam>
/// <param name="func">要执行的函数</param>
/// <param name="defaultValue">默认返回值</param>
/// <param name="operationName">操作名称</param>
/// <param name="timeout">超时时间毫秒默认5000ms</param>
/// <returns>执行结果或默认值</returns>
protected async Task<T> SafeExecuteAsync<T>(Func<T> func, T defaultValue = default(T), string operationName = "操作", int timeout = 5000)
{
if (func == null)
{
LogManager.Warning($"[ViewModel] SafeExecuteAsync接收到空函数: {operationName}");
return defaultValue;
}
try
{
return await _uiStateManager.ExecuteUIUpdateAsync(func, timeout);
}
catch (Exception ex)
{
LogManager.Error($"[ViewModel] {operationName}异步执行失败: {ex.Message}");
LogManager.Error($"[ViewModel] 堆栈信息: {ex.StackTrace}");
return defaultValue;
}
}
#endregion
#region
/// <summary>
/// 设置主ViewModel引用
/// </summary>
/// <param name="mainViewModel">主ViewModel实例</param>
protected void SetMainViewModel(LogisticsControlViewModel mainViewModel)
{
_mainViewModel = mainViewModel;
}
/// <summary>
/// 更新统一状态栏(简单版本,不显示进度条)
/// </summary>
/// <param name="message">状态消息</param>
protected void UpdateMainStatus(string message)
{
try
{
// 如果有主ViewModel引用更新统一状态栏
if (_mainViewModel != null)
{
_mainViewModel.UpdateStatus(message);
}
}
catch (Exception ex)
{
LogManager.Error($"更新统一状态栏失败: {ex.Message}", ex);
}
}
/// <summary>
/// 更新统一状态栏(支持百分比进度)
/// </summary>
/// <param name="message">状态消息</param>
/// <param name="percentage">进度百分比</param>
protected void UpdateMainStatus(string message, double percentage)
{
try
{
// 如果有主ViewModel引用更新统一状态栏
if (_mainViewModel != null)
{
_mainViewModel.UpdateStatus(message, percentage);
}
}
catch (Exception ex)
{
LogManager.Error($"更新统一状态栏失败: {ex.Message}", ex);
}
}
/// <summary>
/// 更新统一状态栏(完整版本,支持不确定进度)
/// </summary>
/// <param name="message">状态消息</param>
/// <param name="progress">进度值(-1表示不确定进度</param>
/// <param name="isProcessing">是否正在处理(可选)</param>
protected void UpdateMainStatus(string message, double progress = -1, bool? isProcessing = null)
{
try
{
// 如果有主ViewModel引用更新统一状态栏
if (_mainViewModel != null)
{
_mainViewModel.UpdateStatus(message, progress, isProcessing);
}
}
catch (Exception ex)
{
LogManager.Error($"更新统一状态栏失败: {ex.Message}", ex);
}
}
#endregion
}
/// <summary>
/// 属性更新模式枚举
/// </summary>
public enum PropertyUpdateMode
{
/// <summary>
/// 立即更新 - 传统模式,立即触发属性变更通知
/// </summary>
Immediate,
/// <summary>
/// 延迟更新 - 将快速连续的更新合并,在指定延迟后统一触发
/// </summary>
Delayed,
/// <summary>
/// 条件更新 - 根据预配置的条件和频率限制决定是否触发更新
/// </summary>
Conditional
}
}