diff --git a/NavisworksTransportPlugin.csproj b/NavisworksTransportPlugin.csproj
index e524645..795647e 100644
--- a/NavisworksTransportPlugin.csproj
+++ b/NavisworksTransportPlugin.csproj
@@ -225,6 +225,9 @@
+
+
+
diff --git a/src/Core/PathPlanningManager.cs b/src/Core/PathPlanningManager.cs
index 184b923..35c420c 100644
--- a/src/Core/PathPlanningManager.cs
+++ b/src/Core/PathPlanningManager.cs
@@ -681,39 +681,17 @@ namespace NavisworksTransport
// 1. 停用ToolPlugin并清理事件订阅
DeactivateToolPlugin();
- // 2. 额外的事件订阅清理 - 确保所有可能的重复订阅都被清除
- LogManager.WriteLog("[事件清理] 执行额外的事件订阅清理");
+ // 2. 简化的事件订阅清理 - 移除危险的反射操作
+ LogManager.WriteLog("[事件清理] 执行安全的事件订阅清理");
try
{
- // 移除所有可能的OnToolPluginMouseClicked订阅
- var mouseClickedEvent = typeof(PathClickToolPlugin).GetEvent("MouseClicked");
- if (mouseClickedEvent != null)
- {
- var eventField = typeof(PathClickToolPlugin).GetField("MouseClicked",
- System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
- if (eventField != null)
- {
- var currentDelegate = (MulticastDelegate)eventField.GetValue(null);
- if (currentDelegate != null)
- {
- var invocationList = currentDelegate.GetInvocationList();
- LogManager.WriteLog($"[事件清理] 发现 {invocationList.Length} 个事件订阅者");
-
- foreach (var handler in invocationList)
- {
- if (handler.Target == this && handler.Method.Name == "OnToolPluginMouseClicked")
- {
- PathClickToolPlugin.MouseClicked -= OnToolPluginMouseClicked;
- LogManager.WriteLog($"[事件清理] 移除了PathPlanningManager.OnToolPluginMouseClicked订阅");
- }
- }
- }
- }
- }
+ // 安全地移除事件订阅,多次取消订阅同一处理程序是安全的
+ PathClickToolPlugin.MouseClicked -= OnToolPluginMouseClicked;
+ LogManager.WriteLog("[事件清理] 已安全移除PathPlanningManager.OnToolPluginMouseClicked订阅");
}
catch (Exception cleanupEx)
{
- LogManager.WriteLog($"[事件清理] 额外清理过程异常: {cleanupEx.Message}");
+ LogManager.WriteLog($"[事件清理] 事件清理过程异常: {cleanupEx.Message}");
}
// 注意:移除了PathEditState设置,StopClickTool只管理工具插件状态,不修改业务逻辑状态
@@ -2702,6 +2680,47 @@ namespace NavisworksTransport
}
}
+ ///
+ /// 强制重新初始化ToolPlugin(公共接口,避免反射调用)
+ ///
+ /// 是否订阅事件
+ /// 初始化是否成功
+ public bool ForceReinitializeToolPlugin(bool subscribeToEvents = false)
+ {
+ try
+ {
+ LogManager.WriteLog($"[工具插件重初始化] 开始强制重新初始化ToolPlugin,订阅事件: {subscribeToEvents}");
+
+ // 1. 停用当前ToolPlugin
+ bool deactivated = DeactivateToolPlugin();
+ LogManager.WriteLog($"[工具插件重初始化] 停用结果: {deactivated}");
+
+ // 2. 强制重置激活状态
+ _isToolPluginActive = false;
+ LogManager.WriteLog("[工具插件重初始化] 已重置激活状态标志");
+
+ // 3. 重新激活ToolPlugin
+ bool activated = ActivateToolPlugin(subscribeToEvents);
+ LogManager.WriteLog($"[工具插件重初始化] 激活结果(事件订阅: {subscribeToEvents}): {activated}");
+
+ if (activated)
+ {
+ LogManager.WriteLog("[工具插件重初始化] ToolPlugin重新初始化成功,已获得鼠标焦点");
+ }
+ else
+ {
+ LogManager.WriteLog("[工具插件重初始化] ToolPlugin激活失败");
+ }
+
+ return activated;
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"[工具插件重初始化] 重新初始化ToolPlugin失败: {ex.Message}", ex);
+ return false;
+ }
+ }
+
#endregion
#region 自动路径规划辅助方法
@@ -3157,6 +3176,14 @@ namespace NavisworksTransport
}
}
+ ///
+ /// 检查是否有任何网格可视化已启用
+ ///
+ public bool IsAnyGridVisualizationEnabled
+ {
+ get { return _showWalkableGrid || _showObstacleGrid || _showUnknownGrid; }
+ }
+
///
/// 刷新网格可视化(根据当前设置重新显示)
///
diff --git a/src/Core/PathPointRenderPlugin.cs b/src/Core/PathPointRenderPlugin.cs
index 96d4cd8..47020b4 100644
--- a/src/Core/PathPointRenderPlugin.cs
+++ b/src/Core/PathPointRenderPlugin.cs
@@ -436,25 +436,56 @@ namespace NavisworksTransport
/// 要保留的路径ID列表
public void ClearPathsExcept(params string[] excludedPathIds)
{
- lock (_lockObject)
+ try
{
- var excludedSet = new HashSet(excludedPathIds);
- var toRemove = _pathVisualizations.Keys.Where(id => !excludedSet.Contains(id)).ToList();
-
- int removedCount = 0;
- foreach (var pathId in toRemove)
+ lock (_lockObject)
{
- if (_pathVisualizations.Remove(pathId))
+ // 防御性编程:处理空参数
+ if (excludedPathIds == null)
{
- removedCount++;
+ excludedPathIds = new string[0];
+ }
+
+ var excludedSet = new HashSet(excludedPathIds.Where(id => !string.IsNullOrEmpty(id)));
+ var toRemove = _pathVisualizations.Keys.Where(id => !excludedSet.Contains(id)).ToList();
+
+ // 记录当前状态
+ LogManager.WriteLog($"[选择性清空] 当前路径数: {_pathVisualizations.Count}, 排除路径数: {excludedSet.Count}, 待清理路径数: {toRemove.Count}");
+
+ // 检查排除的路径是否实际存在
+ var existingExcluded = excludedSet.Where(id => _pathVisualizations.ContainsKey(id)).ToList();
+ var nonExistingExcluded = excludedSet.Where(id => !_pathVisualizations.ContainsKey(id)).ToList();
+
+ if (nonExistingExcluded.Any())
+ {
+ LogManager.WriteLog($"[选择性清空] 注意:尝试保留的路径不存在: {string.Join(", ", nonExistingExcluded)}");
+ }
+
+ if (existingExcluded.Any())
+ {
+ LogManager.WriteLog($"[选择性清空] 将保留的现有路径: {string.Join(", ", existingExcluded)}");
+ }
+
+ int removedCount = 0;
+ foreach (var pathId in toRemove)
+ {
+ if (_pathVisualizations.Remove(pathId))
+ {
+ removedCount++;
+ }
+ }
+
+ LogManager.WriteLog($"[选择性清空] 成功清空{removedCount}个路径,保留{_pathVisualizations.Count}个路径");
+ if (removedCount > 0)
+ {
+ RequestViewRefresh();
}
}
-
- LogManager.WriteLog($"[选择性清空] 清空{removedCount}个路径,保留{excludedSet.Count}个路径");
- if (removedCount > 0)
- {
- RequestViewRefresh();
- }
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"[选择性清空] 清理路径时发生异常: {ex.Message}", ex);
+ // 即使发生异常也不抛出,避免影响主流程
}
}
diff --git a/src/Core/UIUpdate/Updates/ViewModelRefreshOperation.cs b/src/Core/UIUpdate/Updates/ViewModelRefreshOperation.cs
index 6474d96..f653e8b 100644
--- a/src/Core/UIUpdate/Updates/ViewModelRefreshOperation.cs
+++ b/src/Core/UIUpdate/Updates/ViewModelRefreshOperation.cs
@@ -2,6 +2,8 @@ using System;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
+using NavisworksTransport.UI.WPF.Interfaces;
+using NavisworksTransport.Utils;
namespace NavisworksTransport.Core.UIUpdate.Updates
{
@@ -89,28 +91,30 @@ namespace NavisworksTransport.Core.UIUpdate.Updates
await uiStateManager.ExecuteUIUpdateAsync(() =>
{
- // 通过反射调用OnPropertyChanged方法(如果ViewModel是ViewModelBase的子类)
- var onPropertyChangedMethod = ViewModel.GetType().GetMethod("OnPropertyChanged",
- System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Protected);
-
- if (onPropertyChangedMethod != null)
+ // 优先使用IPropertyChangeNotifier接口(安全方式)
+ if (ViewModel is IPropertyChangeNotifier notifier)
{
- onPropertyChangedMethod.Invoke(ViewModel, new object[] { PropertyName });
+ notifier.NotifyPropertyChanged(PropertyName);
}
else
{
- // 如果没有找到OnPropertyChanged方法,尝试直接触发PropertyChanged事件
- var eventField = ViewModel.GetType().GetField("PropertyChanged",
- System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
-
- if (eventField != null)
+ // 如果ViewModel不实现IPropertyChangeNotifier,直接触发PropertyChanged事件
+ // 这是最后的备用方案,避免使用反射
+ try
{
- var eventDelegate = eventField.GetValue(ViewModel) as PropertyChangedEventHandler;
- eventDelegate?.Invoke(ViewModel, new PropertyChangedEventArgs(PropertyName));
+ // 创建PropertyChangedEventArgs并尝试通过事件触发
+ var eventArgs = new PropertyChangedEventArgs(PropertyName);
+
+ // 如果ViewModel有公共的PropertyChanged事件,我们可以通过显式访问来触发
+ // 但是由于事件的限制,我们无法从外部直接调用事件
+ // 这种情况下记录警告,提醒开发者ViewModel应该实现IPropertyChangeNotifier
+ LogManager.Warning($"ViewModel ({ViewModel.GetType().Name}) 未实现IPropertyChangeNotifier接口,无法安全触发属性变更通知");
+ throw new InvalidOperationException($"ViewModel必须实现IPropertyChangeNotifier接口才能使用ViewModelRefreshOperation");
}
- else
+ catch (Exception ex)
{
- throw new InvalidOperationException("无法找到触发PropertyChanged事件的方法");
+ LogManager.Error($"触发PropertyChanged事件失败: {ex.Message}");
+ throw new InvalidOperationException("无法找到触发PropertyChanged事件的方法,请确保ViewModel实现IPropertyChangeNotifier接口");
}
}
}, context.TimeoutMilliseconds);
diff --git a/src/PathPlanning/GridMapGenerator.cs b/src/PathPlanning/GridMapGenerator.cs
index cd7d272..2912486 100644
--- a/src/PathPlanning/GridMapGenerator.cs
+++ b/src/PathPlanning/GridMapGenerator.cs
@@ -1120,103 +1120,105 @@ namespace NavisworksTransport.PathPlanning
LogManager.Info($"[包围盒障碍物处理] 输入统计 - 总模型项: {totalItems}, 将排除通道元素: {channelItemsSet.Count}");
+ // 临时修改:注释掉并行处理以避免线程安全问题
// 使用并行处理提高性能,使用50%的CPU内核以平衡性能和稳定性
- var lockObject = new object();
- Parallel.ForEach(allItems, new ParallelOptions { MaxDegreeOfParallelism = Math.Max(1, Environment.ProcessorCount / 2) }, item =>
+ // var lockObject = new object();
+ // Parallel.ForEach(allItems, new ParallelOptions { MaxDegreeOfParallelism = Math.Max(1, Environment.ProcessorCount / 2) }, item =>
+
+ // 改为单线程处理
+ foreach (var item in allItems)
{
try
{
- Interlocked.Increment(ref processedItems);
+ processedItems++; // 改为普通递增
// 1. 排除通道项(包括容器节点和子节点)
if (channelItemsSet.Contains(item) || IsChildOfChannelItems(item, channelItemsSet))
{
- Interlocked.Increment(ref channelExcludedItems);
- return;
+ channelExcludedItems++; // 改为普通递增
+ continue; // 改为continue
}
// 2. 检查是否有几何体,只对有几何体的元素进行处理
if (!item.HasGeometry)
{
- Interlocked.Increment(ref noGeometryItems);
- return;
+ noGeometryItems++; // 改为普通递增
+ continue; // 改为continue
}
// 2.5 检查是否是容器节点(有子节点的元素通常是组/层级)
// 容器节点的包围盒会包含所有子元素,不应作为障碍物
if (item.Children.Any())
{
- Interlocked.Increment(ref containerItems);
- return; // 跳过容器节点
+ containerItems++; // 改为普通递增
+ continue; // 跳过容器节点,改为continue
}
// 3. 获取包围盒
var bbox = item.BoundingBox();
if (bbox == null)
{
- Interlocked.Increment(ref noBoundsItems);
- return;
+ noBoundsItems++; // 改为普通递增
+ continue; // 改为continue
}
// 4. 检查高度范围(重要优化:提前过滤不相关的模型项)
if (!IsInScanHeightRange(bbox, gridMap, scanHeight))
{
- Interlocked.Increment(ref outOfHeightRangeItems);
- return;
+ outOfHeightRangeItems++; // 改为普通递增
+ continue; // 改为continue
}
// 5. 计算包围盒覆盖的网格单元
var coveredCells = CalculateBoundingBoxGridCoverage(bbox, gridMap);
if (coveredCells.Count == 0)
{
- return; // 没有覆盖任何网格单元
+ continue; // 没有覆盖任何网格单元,改为continue
}
- // 6. 更新网格状态和高度信息(线程安全)
+ // 6. 更新网格状态和高度信息(移除线程安全锁)
var updatedCells = 0;
foreach (var (x, y) in coveredCells)
{
- lock (lockObject) // 确保网格更新的线程安全
+ // 移除lock,单线程不需要锁
+ var cell = gridMap.Cells[x, y];
+
+ // 只更新通道网格,跳过已是障碍物的网格
+ if (cell.CellType == CategoryAttributeManager.LogisticsElementType.通道 && cell.IsInChannel)
{
- var cell = gridMap.Cells[x, y];
+ // 标记为障碍物
+ cell.IsWalkable = false;
+ cell.CellType = CategoryAttributeManager.LogisticsElementType.障碍物;
+ cell.Cost = double.MaxValue;
+ cell.IsInChannel = false;
+ cell.RelatedModelItem = item;
- // 只更新通道网格,跳过已是障碍物的网格
- if (cell.CellType == CategoryAttributeManager.LogisticsElementType.通道 && cell.IsInChannel)
- {
- // 标记为障碍物
- cell.IsWalkable = false;
- cell.CellType = CategoryAttributeManager.LogisticsElementType.障碍物;
- cell.Cost = double.MaxValue;
- cell.IsInChannel = false;
- cell.RelatedModelItem = item;
-
- // 记录高度信息(支持未来多楼层扩展)
- if (cell.PassableHeights == null)
- cell.PassableHeights = new List();
-
- // 计算相对于通道地面的高度区间
- var groundHeight = cell.WorldPosition.Z; // 假设WorldPosition已设置为地面高度
- cell.PassableHeights.Add(new HeightInterval(
- bbox.Min.Z - groundHeight,
- bbox.Max.Z - groundHeight
- ));
-
- gridMap.Cells[x, y] = cell;
- updatedCells++;
- }
+ // 记录高度信息(支持未来多楼层扩展)
+ if (cell.PassableHeights == null)
+ cell.PassableHeights = new List();
+
+ // 计算相对于通道地面的高度区间
+ var groundHeight = cell.WorldPosition.Z; // 假设WorldPosition已设置为地面高度
+ cell.PassableHeights.Add(new HeightInterval(
+ bbox.Min.Z - groundHeight,
+ bbox.Max.Z - groundHeight
+ ));
+
+ gridMap.Cells[x, y] = cell;
+ updatedCells++;
}
}
if (updatedCells > 0)
{
- Interlocked.Increment(ref obstacleItems);
+ obstacleItems++; // 改为普通递增
}
}
catch (Exception ex)
{
LogManager.Debug($"[包围盒障碍物处理] 处理模型项失败: {item?.DisplayName ?? "NULL"}, {ex.Message}");
}
- });
+ }
// 输出详细统计信息
var elapsed = (DateTime.Now - startTime).TotalMilliseconds;
diff --git a/src/UI/WPF/Interfaces/IPropertyChangeNotifier.cs b/src/UI/WPF/Interfaces/IPropertyChangeNotifier.cs
new file mode 100644
index 0000000..3ca23ea
--- /dev/null
+++ b/src/UI/WPF/Interfaces/IPropertyChangeNotifier.cs
@@ -0,0 +1,17 @@
+using System.ComponentModel;
+
+namespace NavisworksTransport.UI.WPF.Interfaces
+{
+ ///
+ /// 提供属性变更通知接口,允许外部组件安全地触发属性变更事件
+ /// 用于替代反射调用,提供更安全的属性变更通知机制
+ ///
+ public interface IPropertyChangeNotifier : INotifyPropertyChanged
+ {
+ ///
+ /// 触发指定属性的变更通知
+ ///
+ /// 属性名称
+ void NotifyPropertyChanged(string propertyName);
+ }
+}
\ No newline at end of file
diff --git a/src/UI/WPF/Services/SmartDataBindingOptimizer.cs b/src/UI/WPF/Services/SmartDataBindingOptimizer.cs
index 89fed65..b927665 100644
--- a/src/UI/WPF/Services/SmartDataBindingOptimizer.cs
+++ b/src/UI/WPF/Services/SmartDataBindingOptimizer.cs
@@ -6,6 +6,8 @@ using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
using NavisworksTransport.UI.WPF.ViewModels;
+using NavisworksTransport.UI.WPF.Interfaces;
+using NavisworksTransport.Utils;
namespace NavisworksTransport.UI.WPF.Services
{
@@ -468,13 +470,20 @@ namespace NavisworksTransport.UI.WPF.Services
{
try
{
- // 使用反射获取PropertyChanged事件并触发
- var propertyChangedField = target.GetType().GetField("PropertyChanged",
- System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
-
- if (propertyChangedField?.GetValue(target) is PropertyChangedEventHandler handler)
+ // 优先使用IPropertyChangeNotifier接口(安全方式,避免反射)
+ if (target is IPropertyChangeNotifier notifier)
{
- handler.Invoke(target, new PropertyChangedEventArgs(propertyName));
+ notifier.NotifyPropertyChanged(propertyName);
+ }
+ else
+ {
+ // 如果目标对象不实现IPropertyChangeNotifier接口,记录警告
+ // 我们无法安全地触发PropertyChanged事件,因为事件只能从内部触发
+ LogManager.Warning($"目标对象 ({target.GetType().Name}) 未实现IPropertyChangeNotifier接口,无法触发属性变更通知: {propertyName}");
+ LogManager.Info("建议更新ViewModel以实现IPropertyChangeNotifier接口,以支持智能数据绑定优化功能");
+
+ // 不使用反射,而是直接跳过这个属性的变更通知
+ // 这是更安全的做法,避免潜在的线程安全问题
}
}
catch (Exception ex)
diff --git a/src/UI/WPF/ViewModels/PathEditingViewModel.cs b/src/UI/WPF/ViewModels/PathEditingViewModel.cs
index b6ba215..ebf8763 100644
--- a/src/UI/WPF/ViewModels/PathEditingViewModel.cs
+++ b/src/UI/WPF/ViewModels/PathEditingViewModel.cs
@@ -832,8 +832,17 @@ namespace NavisworksTransport.UI.WPF.ViewModels
ClearTemporaryAutoPathMarkers();
if (PathPointRenderPlugin.Instance != null)
{
- PathPointRenderPlugin.Instance.ClearPathsExcept("grid_visualization_all", "grid_visualization_channel", "grid_visualization_unknown", "grid_visualization_obstacle"); // 清理历史路径但保留网格可视化
- LogManager.WriteLog("[自动路径规划] 已清理历史路径对象(保留网格可视化)");
+ // 检查是否有网格可视化启用,只在启用时保留网格可视化路径
+ if (_pathPlanningManager?.IsAnyGridVisualizationEnabled == true)
+ {
+ PathPointRenderPlugin.Instance.ClearPathsExcept("grid_visualization_all", "grid_visualization_channel", "grid_visualization_unknown", "grid_visualization_obstacle");
+ LogManager.WriteLog("[自动路径规划] 已清理历史路径对象(保留网格可视化)");
+ }
+ else
+ {
+ PathPointRenderPlugin.Instance.ClearPathsExcept(); // 清理所有路径,不保留任何内容
+ LogManager.WriteLog("[自动路径规划] 已清理历史路径对象(无网格可视化需保留)");
+ }
}
// 调用PathPlanningManager的自动路径规划功能
@@ -910,8 +919,17 @@ namespace NavisworksTransport.UI.WPF.ViewModels
// 确保失败后也清理所有可能的残留路径对象
if (PathPointRenderPlugin.Instance != null)
{
- PathPointRenderPlugin.Instance.ClearPathsExcept("grid_visualization_all", "grid_visualization_channel", "grid_visualization_unknown", "grid_visualization_obstacle");
- LogManager.WriteLog("[自动路径规划] 规划失败后已清理渲染对象(保留网格可视化)");
+ // 检查是否有网格可视化启用,只在启用时保留网格可视化路径
+ if (_pathPlanningManager?.IsAnyGridVisualizationEnabled == true)
+ {
+ PathPointRenderPlugin.Instance.ClearPathsExcept("grid_visualization_all", "grid_visualization_channel", "grid_visualization_unknown", "grid_visualization_obstacle");
+ LogManager.WriteLog("[自动路径规划] 规划失败后已清理渲染对象(保留网格可视化)");
+ }
+ else
+ {
+ PathPointRenderPlugin.Instance.ClearPathsExcept(); // 清理所有路径,不保留任何内容
+ LogManager.WriteLog("[自动路径规划] 规划失败后已清理渲染对象(无网格可视化需保留)");
+ }
}
}
}, "自动路径规划");
@@ -1902,40 +1920,18 @@ namespace NavisworksTransport.UI.WPF.ViewModels
{
LogManager.WriteLog("[事件清理] 开始清理自动路径事件订阅");
- // 移除所有可能的OnAutoPathMouseClicked订阅
+ // 简单安全地移除事件订阅
+ // 由于C#事件处理机制,多次取消订阅同一个处理程序是安全的
+ // 即使处理程序未订阅,取消操作也不会抛出异常
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked;
- // 使用反射检查并清理重复订阅
- var mouseClickedEvent = typeof(PathClickToolPlugin).GetEvent("MouseClicked");
- if (mouseClickedEvent != null)
- {
- var eventField = typeof(PathClickToolPlugin).GetField("MouseClicked",
- System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
- if (eventField != null)
- {
- var currentDelegate = (MulticastDelegate)eventField.GetValue(null);
- if (currentDelegate != null)
- {
- var invocationList = currentDelegate.GetInvocationList();
- LogManager.WriteLog($"[事件清理] 发现 {invocationList.Length} 个事件订阅者");
-
- foreach (var handler in invocationList)
- {
- if (handler.Target == this && handler.Method.Name == "OnAutoPathMouseClicked")
- {
- PathClickToolPlugin.MouseClicked -= (EventHandler)handler;
- LogManager.WriteLog($"[事件清理] 移除了PathEditingViewModel.OnAutoPathMouseClicked订阅");
- }
- }
- }
- }
- }
-
+ LogManager.WriteLog("[事件清理] 已安全移除PathClickToolPlugin.MouseClicked事件订阅");
LogManager.WriteLog("[事件清理] 自动路径事件订阅清理完成");
}
catch (Exception ex)
{
- LogManager.Error($"[事件清理] 清理自动路径事件订阅失败: {ex.Message}");
+ LogManager.Error($"[事件清理] 清理自动路径事件订阅失败: {ex.Message}", ex);
+ // 记录异常但不抛出,避免影响主流程
}
}
@@ -2466,48 +2462,36 @@ namespace NavisworksTransport.UI.WPF.ViewModels
/// 初始化是否成功
private bool ForceReinitializeToolPlugin(bool subscribeToEvents = false)
{
- LogManager.Info($"开始强制重新初始化ToolPlugin以确保获得鼠标焦点,订阅事件: {subscribeToEvents}");
- try
+ try
{
- // 使用反射调用私有方法强制重新激活ToolPlugin
- var deactivateMethod = _pathPlanningManager.GetType().GetMethod("DeactivateToolPlugin",
- System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
- if (deactivateMethod != null)
- {
- deactivateMethod.Invoke(_pathPlanningManager, null);
- LogManager.Info("已停用ToolPlugin");
- }
+ LogManager.Info($"开始强制重新初始化ToolPlugin以确保获得鼠标焦点,订阅事件: {subscribeToEvents}");
- // 重置激活状态标志
- var isActiveField = _pathPlanningManager.GetType().GetField("_isToolPluginActive",
- System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
- if (isActiveField != null)
+ // 使用PathPlanningManager的公共方法,避免反射调用
+ if (_pathPlanningManager != null)
{
- isActiveField.SetValue(_pathPlanningManager, false);
- LogManager.Info("已重置ToolPlugin激活状态标志");
- }
-
- // 重新激活ToolPlugin,根据参数决定是否订阅事件
- var activateMethod = _pathPlanningManager.GetType().GetMethod("ActivateToolPlugin",
- System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
- if (activateMethod != null)
- {
- // 调用带参数的方法,传递subscribeToEvents参数
- var result = activateMethod.Invoke(_pathPlanningManager, new object[] { subscribeToEvents });
- LogManager.Info($"ToolPlugin重新激活结果(事件订阅: {subscribeToEvents}): {result}");
- if (!(bool)result)
+ bool result = _pathPlanningManager.ForceReinitializeToolPlugin(subscribeToEvents);
+ LogManager.Info($"ToolPlugin重新初始化结果(事件订阅: {subscribeToEvents}): {result}");
+
+ if (result)
{
- LogManager.Error("ToolPlugin激活失败");
- return false;
+ LogManager.Info("ToolPlugin重新初始化成功,已获得鼠标焦点");
}
+ else
+ {
+ LogManager.Error("ToolPlugin初始化失败");
+ }
+
+ return result;
+ }
+ else
+ {
+ LogManager.Error("PathPlanningManager为null,无法重新初始化ToolPlugin");
+ return false;
}
-
- LogManager.Info("ToolPlugin重新初始化成功,已获得鼠标焦点");
- return true;
}
catch (Exception ex)
{
- LogManager.Error($"重新初始化ToolPlugin失败: {ex.Message}");
+ LogManager.Error($"重新初始化ToolPlugin失败: {ex.Message}", ex);
return false;
}
}
diff --git a/src/UI/WPF/ViewModels/ViewModelBase.cs b/src/UI/WPF/ViewModels/ViewModelBase.cs
index f5fc864..71c5bbf 100644
--- a/src/UI/WPF/ViewModels/ViewModelBase.cs
+++ b/src/UI/WPF/ViewModels/ViewModelBase.cs
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
using NavisworksTransport.Core;
using NavisworksTransport.Utils;
using NavisworksTransport.UI.WPF.Services;
+using NavisworksTransport.UI.WPF.Interfaces;
namespace NavisworksTransport.UI.WPF.ViewModels
{
@@ -15,7 +16,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
/// 集成UIStateManager提供线程安全的属性更新和防重入机制
/// 集成智能数据绑定优化功能,支持延迟更新、批量更新和条件更新
///
- public abstract class ViewModelBase : INotifyPropertyChanged
+ public abstract class ViewModelBase : IPropertyChangeNotifier
{
#region 字段和属性
@@ -145,6 +146,15 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
}
+ ///
+ /// 公共接口:触发指定属性的变更通知(供外部组件使用,替代反射调用)
+ ///
+ /// 属性名称
+ public virtual void NotifyPropertyChanged(string propertyName)
+ {
+ OnPropertyChanged(propertyName);
+ }
+
///
/// 同步触发属性变更通知(确保在UI线程上执行完成)
///