diff --git a/.serena/cache/csharp/document_symbols_cache_v23-06-25.pkl b/.serena/cache/csharp/document_symbols_cache_v23-06-25.pkl
index 1843f7c..2be3597 100644
Binary files a/.serena/cache/csharp/document_symbols_cache_v23-06-25.pkl and b/.serena/cache/csharp/document_symbols_cache_v23-06-25.pkl differ
diff --git a/NavisworksTransportPlugin.csproj b/NavisworksTransportPlugin.csproj
index 644afd5..dc61700 100644
--- a/NavisworksTransportPlugin.csproj
+++ b/NavisworksTransportPlugin.csproj
@@ -184,6 +184,12 @@
LayerManagementView.xaml
+
+ HelpDialog.xaml
+
+
+ AboutDialog.xaml
+
@@ -258,6 +264,20 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+
+ Designer
+ MSBuild:Compile
+
+
diff --git a/Plugin.csproj b/Plugin.csproj
index 0345b03..417437a 100644
--- a/Plugin.csproj
+++ b/Plugin.csproj
@@ -1,2 +1,31 @@
-
\ No newline at end of file
+
+ Designer
+ MSBuild:Compile
+
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+
+ Designer
+ MSBuild:Compile
+
+
+
+
\ No newline at end of file
diff --git a/doc/guide/design_principles.md b/doc/guide/design_principles.md
index e62899c..68aba20 100644
--- a/doc/guide/design_principles.md
+++ b/doc/guide/design_principles.md
@@ -1235,7 +1235,303 @@ private void ShowPositionCorrectionDialog(Point3D originalPos, Point3D corrected
- 精度要求高的导航系统
- 自动化路径生成工具
-## 13. 线程安全实践经验总结
+## 13. WPF数据绑定最佳实践:避免自定义集合陷阱
+
+### 问题描述
+
+在NavisworksTransport项目中发现了一个经典的WPF数据绑定问题:自定义的 `ThreadSafeObservableCollection` 与WPF标准数据绑定机制不兼容,导致UI显示重复数据。这个问题揭示了"过度工程"的风险以及回归标准实践的重要性。
+
+### 问题根本原因分析
+
+#### 13.1 设计理念冲突
+
+```csharp
+// ❌ 问题:自定义线程安全集合与WPF冲突
+public class ThreadSafeObservableCollection : ObservableCollection
+{
+ // 内部实现复杂的UI线程marshaling
+ private void OnCollectionChanged()
+ {
+ // 自定义的UI线程处理机制
+ _uiStateManager.QueueUIUpdate(() =>
+ {
+ base.OnCollectionChanged(...);
+ });
+ }
+}
+
+// ✅ 解决方案:使用WPF标准集合
+public ObservableCollection PathRoutes { get; set; }
+ = new ObservableCollection();
+```
+
+**核心冲突**:
+- `ThreadSafeObservableCollection`试图提供线程安全,通过内部机制自动将变更marshaling到UI线程
+- WPF数据绑定期望使用标准的`ObservableCollection`,由框架本身处理UI线程marshaling
+- 双重UI线程处理机制导致重复通知和不可预测的行为
+
+#### 13.2 异步处理复杂性
+
+```csharp
+// ❌ 导致问题的异步初始化机制
+public PathRouteViewModel()
+{
+ InitializeDefaults();
+ _ = InitializeAsync(); // "火后不理"的异步调用
+}
+
+public async Task InitializeAsync()
+{
+ await _uiStateManager.ExecuteUIUpdateAsync(() =>
+ {
+ // 异步UI更新可能与同步数据创建产生时序问题
+ Points.CollectionChanged += OnPointsCollectionChanged;
+ _isInitialized = true;
+ });
+}
+```
+
+**时序问题分析**:
+1. 同步的数据创建(RefreshPathRoutes)
+2. 异步的UI初始化(InitializeAsync)
+3. UI更新队列积压(保底定时器强制处理)
+4. 重复的UI更新执行
+
+#### 13.3 事件处理重叠
+
+发现有三个机制同时处理相同的数据变更:
+```csharp
+// 机制1:手动刷新
+RefreshPathRoutes() // 从Core数据创建UI路径点
+
+// 机制2:事件响应
+OnPathPointsListUpdated() // 响应路径点更新事件
+
+// 机制3:路径生成事件
+OnRouteGenerated() // 处理自动路径生成
+
+// 结果:同样的路径点被多次添加到UI
+```
+
+### 完整解决方案
+
+#### 13.4 回归WPF标准实践
+
+```csharp
+// ✅ 正确做法:使用标准ObservableCollection
+public class PathEditingViewModel : ViewModelBase
+{
+ // 路径集合使用标准集合
+ public ObservableCollection PathRoutes { get; private set; }
+ = new ObservableCollection();
+}
+
+public class PathRouteViewModel : ViewModelBase
+{
+ // 路径点集合也使用标准集合
+ public ObservableCollection Points { get; private set; }
+ = new ObservableCollection();
+
+ // 简化初始化:同步完成,无异步复杂性
+ public PathRouteViewModel()
+ {
+ InitializeDefaults();
+ CompleteInitialization();
+ }
+
+ private void CompleteInitialization()
+ {
+ // 直接订阅事件,无需异步
+ Points.CollectionChanged += OnPointsCollectionChanged;
+ _isInitialized = true;
+ }
+}
+```
+
+#### 13.5 职责分离和重复检查
+
+```csharp
+// ✅ 事件处理器包含重复检查逻辑
+private async void OnPathPointsListUpdated(object sender, PathPointsListUpdatedEventArgs e)
+{
+ if (e?.Route == null) return;
+
+ await SafeExecuteAsync(() =>
+ {
+ var pathViewModel = PathRoutes.FirstOrDefault(p => p.Name == e.Route.Name);
+ if (pathViewModel != null)
+ {
+ // 关键:检查是否需要更新,避免重复处理
+ if (pathViewModel.Points.Count == e.Route.Points.Count)
+ {
+ LogManager.Info($"路径点数量已正确({pathViewModel.Points.Count}),跳过重复更新");
+ return;
+ }
+
+ // 执行实际更新
+ pathViewModel.Points.Clear();
+ foreach (var point in e.Route.Points)
+ {
+ // 添加路径点...
+ }
+ }
+ }, "处理路径点列表更新事件");
+}
+```
+
+### 关键经验教训
+
+#### 13.6 过度工程的陷阱
+
+**问题**:试图通过复杂的自定义机制"改进"框架的标准行为
+**结果**:引入了与框架机制的冲突,造成更多问题
+**教训**:WPF的`ObservableCollection`已经是充分测试的成熟解决方案
+
+```csharp
+// ❌ 过度设计:复杂的自定义线程安全集合
+public class ThreadSafeObservableCollection : ObservableCollection
+{
+ private readonly UIStateManager _uiStateManager;
+ private readonly object _lockObject = new object();
+
+ protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
+ {
+ // 复杂的线程安全逻辑
+ if (_uiStateManager != null)
+ {
+ _uiStateManager.QueueUIUpdate(() => base.OnCollectionChanged(e));
+ }
+ // 与WPF绑定机制产生冲突
+ }
+}
+
+// ✅ 简单有效:使用标准解决方案
+public ObservableCollection Items { get; private set; } = new ObservableCollection();
+```
+
+#### 13.7 线程安全的正确处理方式
+
+在WPF中,正确的线程安全做法是:
+- **数据操作**在适当的线程中执行
+- **UI更新**统一通过`Dispatcher.Invoke`或`UIStateManager`在UI线程执行
+- **不要在集合层面**实现线程安全,而是在操作层面控制
+
+```csharp
+// ✅ 正确的线程安全模式
+public async Task AddPathAsync(PathRouteViewModel path)
+{
+ await _uiStateManager.ExecuteUIUpdateAsync(() =>
+ {
+ PathRoutes.Add(path); // 在UI线程上操作标准集合
+ });
+}
+```
+
+#### 13.8 调试复杂问题的方法论
+
+从这个案例中学到的调试方法:
+1. **详细日志追踪**:记录事件时序和调用栈
+2. **识别异步副作用**:关注"火后不理"的异步调用
+3. **分析处理机制重叠**:多个组件处理相同数据的情况
+4. **回归简单方案**:当复杂方案出问题时,考虑标准做法
+
+### 设计原则总结
+
+#### 13.9 集合使用原则
+
+```csharp
+// ✅ WPF UI绑定:使用标准ObservableCollection
+public ObservableCollection Items { get; private set; }
+ = new ObservableCollection();
+
+// ✅ 后台数据处理:可以使用线程安全集合
+private readonly ConcurrentBag _processingQueue
+ = new ConcurrentBag();
+
+// ✅ UI更新时:统一在UI线程操作
+public async Task UpdateUI(List newData)
+{
+ await _uiStateManager.ExecuteUIUpdateAsync(() =>
+ {
+ Items.Clear();
+ foreach (var item in newData)
+ {
+ Items.Add(new ItemViewModel(item));
+ }
+ });
+}
+```
+
+#### 13.10 ViewModel设计原则
+
+```csharp
+// ✅ 保持ViewModel简单和同步
+public class SimpleViewModel : ViewModelBase
+{
+ public SimpleViewModel()
+ {
+ // 同步初始化,避免复杂的异步逻辑
+ InitializeProperties();
+ SubscribeToEvents();
+ }
+
+ // ✅ 使用标准属性更改通知
+ private string _status;
+ public string Status
+ {
+ get => _status;
+ set => SetProperty(ref _status, value);
+ }
+}
+
+// ❌ 避免复杂的异步初始化
+public class ComplexViewModel : ViewModelBase
+{
+ public ComplexViewModel()
+ {
+ _ = InitializeAsync(); // 导致时序问题
+ }
+
+ private async Task InitializeAsync()
+ {
+ // 复杂的异步初始化逻辑
+ // 可能与UI绑定产生冲突
+ }
+}
+```
+
+### 适用场景和建议
+
+#### 13.11 何时使用标准集合
+
+✅ **使用ObservableCollection的场景**:
+- WPF数据绑定
+- UI列表显示
+- 用户交互集合
+- ViewModel中的集合属性
+
+✅ **使用线程安全集合的场景**:
+- 后台数据处理
+- 多线程生产者-消费者模式
+- 缓存和队列
+- 非UI相关的数据结构
+
+#### 13.12 实施检查清单
+
+在代码审查中重点检查:
+- [ ] ViewModel中的集合是否使用标准`ObservableCollection`?
+- [ ] 是否避免了"过度设计"的自定义集合?
+- [ ] UI更新是否统一在UI线程执行?
+- [ ] 是否存在多个机制处理相同数据的情况?
+- [ ] 异步初始化是否真的必要?
+
+### 结论
+
+这个UI重复问题的根本原因是**试图通过自定义的`ThreadSafeObservableCollection`来"改进"WPF的标准数据绑定,但这种改进引入了与框架机制的冲突,导致重复的UI更新和不可预测的行为**。
+
+解决方案是**回归WPF的最佳实践,使用标准集合和框架提供的机制**。这个案例很好地说明了在软件开发中,简单、标准的解决方案往往比复杂的自定义方案更可靠。
+
+## 14. 线程安全实践经验总结
### 问题描述
diff --git a/doc/working/ThreadSafeObservableCollection_Migration_Plan.md b/doc/working/ThreadSafeObservableCollection_Migration_Plan.md
new file mode 100644
index 0000000..ab7bb8b
--- /dev/null
+++ b/doc/working/ThreadSafeObservableCollection_Migration_Plan.md
@@ -0,0 +1,323 @@
+# ThreadSafeObservableCollection 全面迁移计划
+
+## 问题背景
+
+在解决UI重复显示问题的过程中,我们发现了 `ThreadSafeObservableCollection` 与WPF标准数据绑定机制不兼容的根本问题。虽然已经在关键文件(`PathEditingViewModel` 和 `PathRouteViewModel`)中成功修复,但项目中仍有大量使用 `ThreadSafeObservableCollection` 的地方需要评估和迁移。
+
+## 使用现状分析
+
+通过代码搜索发现,项目中 `ThreadSafeObservableCollection` 的使用分布如下:
+
+### 使用位置统计
+- **ViewModels**: 8个文件使用了约15处
+ - `LogisticsControlViewModel.cs` (4处)
+ - `LayerManagementViewModel.cs` (5处)
+ - `ModelSettingsViewModel.cs` (3处)
+ - `AnimationControlViewModel.cs` (1处)
+ - `SystemManagementViewModel.cs` (1处)
+ - `LogisticsControlViewModelcopy.cs` (5处)
+ - ✅ `PathEditingViewModel.cs` (已迁移)
+ - ✅ `PathRouteViewModel.cs` (已迁移)
+
+- **核心基础设施**:
+ - `src/UI/WPF/Collections/ThreadSafeObservableCollection.cs` - 核心实现
+ - `src/Core/UIUpdate/Updates/CollectionUpdateOperation.cs` - UIUpdate系统支持
+ - `src/UI/WPF/Services/DataBindingBestPractices.cs` - 最佳实践指导
+
+- **测试文件**:
+ - `UnitTests/Collections/ThreadSafeObservableCollectionBasicTests.cs`
+
+## 核心问题分析
+
+### 1. WPF数据绑定冲突
+`ThreadSafeObservableCollection` 试图提供线程安全,通过内部机制自动将变更marshaling到UI线程,但与WPF数据绑定期望的标准机制产生冲突:
+
+```csharp
+// ❌ 问题:双重UI线程处理机制
+ThreadSafeObservableCollection 内部处理 + WPF数据绑定机制 = 重复UI更新
+```
+
+### 2. 过度工程陷阱
+自定义的线程安全集合引入了与框架机制的冲突,造成比解决的问题更多的问题。
+
+## 迁移策略
+
+### Phase 1: 分类评估 (不破坏现有功能)
+
+#### 1.1 需要迁移的场景 - WPF UI绑定
+**原则**: 用于WPF数据绑定的集合应使用标准 `ObservableCollection`
+
+**需要迁移的文件**:
+- ✅ `PathEditingViewModel.cs` (已完成)
+- ✅ `PathRouteViewModel.cs` (已完成)
+- `LogisticsControlViewModel.cs`
+- `LayerManagementViewModel.cs`
+- `ModelSettingsViewModel.cs`
+- `AnimationControlViewModel.cs`
+- `SystemManagementViewModel.cs`
+
+#### 1.2 建议保留的场景 - 后台数据处理
+**原则**: 非UI绑定的数据集合可以继续使用线程安全集合
+
+**保留使用的场景**:
+- 多线程后台处理的临时数据
+- 缓存和队列等数据结构
+- 不直接绑定到UI的数据管理
+
+### Phase 2: 渐进式迁移 (确保稳定性)
+
+#### 迁移步骤模板
+
+对于每个需要迁移的ViewModel:
+
+1. **准备工作**
+ ```bash
+ # 备份当前文件
+ copy OriginalViewModel.cs OriginalViewModel.cs.backup
+ ```
+
+2. **代码修改**
+ ```csharp
+ // 替换集合声明
+ // ❌ 修改前
+ public ThreadSafeObservableCollection Items { get; private set; }
+ = new ThreadSafeObservableCollection();
+
+ // ✅ 修改后
+ public ObservableCollection Items { get; private set; }
+ = new ObservableCollection();
+ ```
+
+3. **简化初始化**
+ ```csharp
+ // ❌ 复杂的异步初始化
+ public ViewModel()
+ {
+ InitializeDefaults();
+ _ = InitializeAsync(); // "火后不理"的异步调用
+ }
+
+ // ✅ 简单的同步初始化
+ public ViewModel()
+ {
+ InitializeDefaults();
+ CompleteInitialization();
+ }
+ ```
+
+4. **添加重复检查**
+ ```csharp
+ // ✅ 事件处理器包含重复检查逻辑
+ private async void OnDataUpdated(object sender, DataUpdatedEventArgs e)
+ {
+ if (e?.Data == null) return;
+
+ await SafeExecuteAsync(() =>
+ {
+ // 关键:检查是否需要更新,避免重复处理
+ if (Items.Count == e.Data.Count)
+ {
+ LogManager.Info($"数据数量已正确({Items.Count}),跳过重复更新");
+ return;
+ }
+
+ // 执行实际更新
+ Items.Clear();
+ foreach (var item in e.Data)
+ {
+ Items.Add(item);
+ }
+ }, "处理数据更新事件");
+ }
+ ```
+
+5. **测试验证**
+ - 编译测试:确保无编译错误
+ - 功能测试:验证UI显示正常,无重复数据
+ - 性能测试:确认UI响应性能
+
+#### 迁移优先级
+
+1. **高优先级** - 直接用于WPF数据绑定,有UI重复显示风险
+ - `LogisticsControlViewModel.cs`
+ - `LayerManagementViewModel.cs`
+ - `ModelSettingsViewModel.cs`
+
+2. **中优先级** - 间接影响UI显示
+ - `AnimationControlViewModel.cs`
+ - `SystemManagementViewModel.cs`
+
+3. **低优先级** - 纯后台数据处理,无直接UI影响
+ - 保留现有实现或根据具体需求决定
+
+### Phase 3: 架构优化 (长期改进)
+
+#### 3.1 使用原则制定
+
+建立清晰的集合选择原则:
+
+```csharp
+// ✅ WPF UI绑定场景
+public ObservableCollection UIBoundItems { get; private set; }
+ = new ObservableCollection();
+
+// ✅ 后台数据处理场景
+private readonly ConcurrentBag _processingQueue
+ = new ConcurrentBag();
+
+// ✅ UI更新统一处理
+public async Task UpdateUI(List newData)
+{
+ await _uiStateManager.ExecuteUIUpdateAsync(() =>
+ {
+ UIBoundItems.Clear();
+ foreach (var item in newData)
+ {
+ UIBoundItems.Add(item);
+ }
+ });
+}
+```
+
+#### 3.2 重构建议
+
+1. **保持向后兼容**
+ - 继续维护 `ThreadSafeObservableCollection` 类
+ - 保留 `CollectionUpdateOperation` 的支持
+ - 更新文档说明使用场景
+
+2. **架构清晰化**
+ - WPF UI绑定 → 标准 `ObservableCollection`
+ - 后台数据处理 → `ThreadSafeObservableCollection` 或 `ConcurrentCollection`
+ - 线程安全更新 → 统一通过 `UIStateManager` 处理
+
+## 详细迁移计划
+
+### 第一批迁移: LogisticsControlViewModel
+```csharp
+// 需要迁移的属性:
+- LogisticsModels (ThreadSafeObservableCollection)
+- AvailableCategories (ThreadSafeObservableCollection)
+- AvailableFrameRates (ThreadSafeObservableCollection)
+```
+
+**验证项目**:
+- [ ] 物流模型显示正常
+- [ ] 分类选择功能正常
+- [ ] 帧率设置功能正常
+- [ ] 无UI重复显示问题
+
+### 第二批迁移: LayerManagementViewModel
+```csharp
+// 需要迁移的属性:
+- AvailableAttributes (ThreadSafeObservableCollection)
+- DepthOptions (ThreadSafeObservableCollection)
+- SplitStrategies (ThreadSafeObservableCollection)
+- SplitPreviewResults (ThreadSafeObservableCollection)
+```
+
+**验证项目**:
+- [ ] 图层管理界面显示正常
+- [ ] 属性选择功能正常
+- [ ] 模型分割预览功能正常
+- [ ] 分割策略选择正常
+
+### 第三批迁移: ModelSettingsViewModel
+```csharp
+// 需要迁移的属性:
+- AvailableCategories (ThreadSafeObservableCollection)
+- PriorityLevels (ThreadSafeObservableCollection)
+- LogisticsModels (ThreadSafeObservableCollection)
+```
+
+**验证项目**:
+- [ ] 模型设置界面显示正常
+- [ ] 分类设置功能正常
+- [ ] 优先级设置功能正常
+
+### 第四批迁移: 其他ViewModels
+- `AnimationControlViewModel.cs` - AvailableFrameRates
+- `SystemManagementViewModel.cs` - LogLevels
+
+## 风险评估与缓解措施
+
+### 风险1: UI性能问题
+**风险等级**: 中等
+**缓解措施**:
+- 分阶段迁移,每次迁移后进行性能测试
+- 监控UI响应时间,如有问题及时回滚
+
+### 风险2: 多线程并发问题
+**风险等级**: 中等
+**缓解措施**:
+- 保留UIStateManager机制,确保UI更新线程安全
+- 对非UI绑定的数据处理场景保留ThreadSafeObservableCollection
+
+### 风险3: 现有功能破坏
+**风险等级**: 低
+**缓解措施**:
+- 每个ViewModel迁移完成后进行完整功能测试
+- 保留备份文件,支持快速回滚
+- 渐进式迁移,一次只处理一个ViewModel
+
+### 风险4: 团队学习成本
+**风险等级**: 低
+**缓解措施**:
+- 提供清晰的迁移指南和代码示例
+- 在设计文档中明确新的使用原则
+
+## 预期收益
+
+### 短期收益
+1. **消除UI重复显示问题** - 避免双重UI更新机制冲突
+2. **提高代码可靠性** - 使用经过充分测试的标准WPF机制
+3. **简化调试过程** - 减少自定义机制带来的复杂性
+
+### 长期收益
+1. **遵循WPF最佳实践** - 与框架设计理念保持一致
+2. **提高代码可维护性** - 减少自定义实现的维护负担
+3. **改善团队开发效率** - 新团队成员更容易理解标准WPF模式
+
+## 实施时间表
+
+**建议时间安排**:
+- Phase 1 (评估阶段): 已完成
+- Phase 2 (渐进式迁移): 2-4周
+ - 第一批迁移: 1周
+ - 第二批迁移: 1周
+ - 第三、四批迁移: 1-2周
+- Phase 3 (架构优化): 1周
+ - 文档更新和代码清理
+
+**里程碑检查点**:
+- 每批迁移完成后进行功能验证
+- 所有迁移完成后进行全面集成测试
+- 最终进行性能和稳定性测试
+
+## 结论
+
+这个迁移计划基于实际发现的UI重复显示问题,采用渐进式、风险可控的方式,在保证现有功能正常的前提下,逐步解决架构问题,最终建立更健壮、更符合WPF最佳实践的集合管理机制。
+
+通过这次迁移,我们不仅解决了具体的技术问题,更重要的是建立了"简单、标准的解决方案往往比复杂的自定义方案更可靠"的架构理念。
+
+---
+
+## 附录
+
+### A. 相关文档
+- [设计原则文档 - WPF数据绑定最佳实践](../guide/design_principles.md#13-wpf数据绑定最佳实践避免自定义集合陷阱)
+- [ThreadSafeObservableCollection实现总结](../memories/threadsafe_observable_collection_implementation.md)
+
+### B. 参考代码示例
+参考已成功迁移的文件:
+- `src/UI/WPF/ViewModels/PathEditingViewModel.cs`
+- `src/UI/WPF/Models/PathRouteViewModel.cs`
+
+### C. 迁移检查清单
+- [ ] 集合声明已更改为ObservableCollection
+- [ ] 构造函数已简化为同步初始化
+- [ ] 事件处理器包含重复检查逻辑
+- [ ] 编译无错误无警告
+- [ ] UI显示功能正常
+- [ ] 无重复数据显示
+- [ ] 性能无明显退化
\ No newline at end of file
diff --git a/src/Commands/ImportPathCommand.cs b/src/Commands/ImportPathCommand.cs
index d77f9a4..5bd3319 100644
--- a/src/Commands/ImportPathCommand.cs
+++ b/src/Commands/ImportPathCommand.cs
@@ -507,34 +507,6 @@ namespace NavisworksTransport.Commands
UpdateProgress(85, "正在完成导入操作...");
ThrowIfCancellationRequested(cancellationToken);
- // 第六阶段:后处理(90%)
- UpdateProgress(90, "正在完成导入后处理...");
-
- try
- {
- await _uiStateManager.ExecuteUIUpdateAsync(() =>
- {
- // 自动选择第一个导入的路径为当前路径
- if (_parameters.AutoSelectFirstRoute && result.ImportedCount > 0)
- {
- var firstImportedRoute = _pathPlanningManager.Routes
- .Where(r => result.ImportedPaths.Any(ip => ip.StartsWith(r.Name)))
- .FirstOrDefault();
-
- if (firstImportedRoute != null)
- {
- _pathPlanningManager.SetCurrentRoute(firstImportedRoute);
- LogInfo($"已自动选择路径为当前路径: {firstImportedRoute.Name}");
- }
- }
- LogInfo("UI状态已刷新");
- });
- }
- catch (Exception refreshEx)
- {
- LogWarning($"刷新UI状态失败: {refreshEx.Message}");
- }
-
// 完成(100%)
UpdateProgress(100, "路径导入完成");
diff --git a/src/Core/MainPlugin.cs b/src/Core/MainPlugin.cs
index 0914061..1c61c0d 100644
--- a/src/Core/MainPlugin.cs
+++ b/src/Core/MainPlugin.cs
@@ -2918,19 +2918,8 @@ namespace NavisworksTransport
refreshPathList(); // 初始加载
- // 监听路径生成事件,自动刷新路径列表
- var activePathManager = PathPlanningManager.GetActivePathManager();
- if (activePathManager != null)
- {
- activePathManager.RouteGenerated += (sender, route) =>
- {
- GlobalExceptionHandler.SafeExecute(() =>
- {
- LogManager.Info($"检测到新路径生成:{route?.Name},自动刷新动画控制面板路径列表");
- refreshPathList();
- }, "路径生成事件处理");
- };
- }
+ // 注意:路径生成事件的UI更新已由PathEditingViewModel处理,避免重复订阅
+ // 如果需要特殊的动画面板刷新逻辑,应该通过其他方式实现
// 生成动画事件处理
createAnimationButton.Click += (sender, e) =>
diff --git a/src/Core/PathPlanningManager.cs b/src/Core/PathPlanningManager.cs
index 249f037..91b5054 100644
--- a/src/Core/PathPlanningManager.cs
+++ b/src/Core/PathPlanningManager.cs
@@ -988,14 +988,15 @@ namespace NavisworksTransport
_routes.Add(route);
RaiseStatusChanged($"已添加路径: {route.Name}", PathPlanningStatusType.Success);
- // 如果当前没有活动路径,设置此路径为活动路径
- if (_currentRoute == null || _currentRoute.Points.Count == 0)
- {
- CurrentRoute = route;
- }
+ // AddRoute只负责添加路径到数据集合,不自动设置当前路径
+ // 路径选择应该通过专门的选择逻辑处理,而不是添加操作的副作用
+ // if (_currentRoute == null || _currentRoute.Points.Count == 0)
+ // {
+ // CurrentRoute = route;
+ // }
- // 触发路径生成事件
- RaiseRouteGenerated(route, RouteGenerationMethod.Manual);
+ // 注释掉多余的路径生成事件调用,Manual类型路径通过UI层的RefreshPathRoutes()统一刷新
+ // RaiseRouteGenerated(route, RouteGenerationMethod.Manual);
return true;
}
diff --git a/src/UI/WPF/LogisticsControlPanel.xaml b/src/UI/WPF/LogisticsControlPanel.xaml
index 0dd91b6..7a697eb 100644
--- a/src/UI/WPF/LogisticsControlPanel.xaml
+++ b/src/UI/WPF/LogisticsControlPanel.xaml
@@ -1,3 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -13,32 +35,60 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/UI/WPF/LogisticsControlPanel.xaml.cs b/src/UI/WPF/LogisticsControlPanel.xaml.cs
index 0ea2dc6..8456a72 100644
--- a/src/UI/WPF/LogisticsControlPanel.xaml.cs
+++ b/src/UI/WPF/LogisticsControlPanel.xaml.cs
@@ -253,8 +253,11 @@ namespace NavisworksTransport.UI.WPF
{
GlobalExceptionHandler.SafeExecute(() =>
{
- MessageBox.Show("物流路径规划插件使用说明:\n\n1. 类别设置:设置对象类别和可见性\n2. 路径编辑:创建和管理3D路径\n3. 动画控制:创建路径动画\n4. 系统管理:插件设置和日志",
- "帮助", MessageBoxButton.OK, MessageBoxImage.Information);
+ var helpDialog = new Views.HelpDialog
+ {
+ Owner = Window.GetWindow(this)
+ };
+ helpDialog.ShowDialog();
}, "显示帮助");
}
@@ -265,8 +268,11 @@ namespace NavisworksTransport.UI.WPF
{
GlobalExceptionHandler.SafeExecute(() =>
{
- MessageBox.Show("物流路径规划插件 v1.0\n\n适用于 Navisworks 2026\n\n功能:3D路径规划、动画创建、碰撞检测",
- "关于插件", MessageBoxButton.OK, MessageBoxImage.Information);
+ var aboutDialog = new Views.AboutDialog
+ {
+ Owner = Window.GetWindow(this)
+ };
+ aboutDialog.ShowDialog();
}, "显示关于");
}
diff --git a/src/UI/WPF/Models/PathRouteViewModel.cs b/src/UI/WPF/Models/PathRouteViewModel.cs
index e08219c..e8874cc 100644
--- a/src/UI/WPF/Models/PathRouteViewModel.cs
+++ b/src/UI/WPF/Models/PathRouteViewModel.cs
@@ -145,7 +145,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
#region 私有字段
private string _name;
- private ThreadSafeObservableCollection _points;
+ private ObservableCollection _points;
private bool _isActive;
private string _description;
private bool _isOptimal;
@@ -181,9 +181,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
///
- /// 路径点集合(线程安全)
+ /// 路径点集合
///
- public ThreadSafeObservableCollection Points
+ public ObservableCollection Points
{
get => _points;
private set => SetProperty(ref _points, value);
@@ -329,8 +329,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
// 初始化默认值
InitializeDefaults();
- // 异步初始化
- _ = InitializeAsync();
+ // 直接完成初始化,不需要异步
+ CompleteInitialization();
LogManager.Debug($"PathRouteViewModel构造函数完成:{_name}");
}
@@ -379,33 +379,43 @@ namespace NavisworksTransport.UI.WPF.ViewModels
_isValidated = false;
_validationStatus = "未验证";
- // 初始化线程安全的点集合
- Points = new ThreadSafeObservableCollection();
+ // 初始化点集合
+ Points = new ObservableCollection();
}
///
- /// 异步初始化方法
+ /// 完成初始化
+ ///
+ private void CompleteInitialization()
+ {
+ try
+ {
+ // 订阅Points集合变更事件
+ if (Points != null)
+ {
+ Points.CollectionChanged += OnPointsCollectionChanged;
+ }
+
+ // 设置初始化完成标志
+ _isInitialized = true;
+ OnPropertyChanged(nameof(IsInitialized));
+
+ LogManager.Debug($"PathRouteViewModel初始化完成:{_name}");
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"PathRouteViewModel初始化异常: {ex.Message}", ex);
+ }
+ }
+
+ ///
+ /// 异步初始化方法(保留用于向后兼容)
///
/// 异步任务
+ [Obsolete("已改为同步初始化,此方法保留用于向后兼容")]
public async Task InitializeAsync()
{
- await SafeExecuteAsync(async () =>
- {
- await _uiStateManager.ExecuteUIUpdateAsync(() =>
- {
- // 订阅Points集合变更事件
- if (Points != null)
- {
- Points.CollectionChanged += OnPointsCollectionChanged;
- }
-
- // 设置初始化完成标志
- _isInitialized = true;
- OnPropertyChanged(nameof(IsInitialized));
-
- LogManager.Debug($"PathRouteViewModel异步初始化完成:{_name}");
- });
- }, "异步初始化PathRouteViewModel");
+ await Task.CompletedTask; // 现在初始化已经在构造函数中同步完成
}
///
@@ -485,7 +495,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
{
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
- Points.AddRange(pointList);
+ foreach (var point in pointList)
+ {
+ Points.Add(point);
+ }
LogManager.Debug($"批量添加{pointList.Count}个路径点到路径 {_name}");
});
}, "批量添加路径点");
@@ -550,7 +563,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
return await Task.Run(() =>
{
double totalLength = 0.0;
- var pointsSnapshot = Points.ToSnapshot();
+ var pointsSnapshot = Points.ToList();
for (int i = 0; i < pointsSnapshot.Count - 1; i++)
{
@@ -612,7 +625,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
// 检查重复点
- var duplicatePoints = Points.ToSnapshot()
+ var duplicatePoints = Points.ToList()
.GroupBy(p => new { p.X, p.Y, p.Z })
.Where(g => g.Count() > 1)
.ToList();
diff --git a/src/UI/WPF/Resources/NavisworksStyles.xaml b/src/UI/WPF/Resources/NavisworksStyles.xaml
new file mode 100644
index 0000000..6855eac
--- /dev/null
+++ b/src/UI/WPF/Resources/NavisworksStyles.xaml
@@ -0,0 +1,195 @@
+
+
+
+
+ #FF2B579A
+ #FF4472C4
+ #FFD4E7FF
+ #FFF8FBFF
+ #FFE7F1FF
+ #FF666666
+ #FF333333
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/UI/WPF/ViewModels/PathEditingViewModel.cs b/src/UI/WPF/ViewModels/PathEditingViewModel.cs
index e83b400..3b88599 100644
--- a/src/UI/WPF/ViewModels/PathEditingViewModel.cs
+++ b/src/UI/WPF/ViewModels/PathEditingViewModel.cs
@@ -5,12 +5,16 @@ using System.Windows;
using System.Windows.Input;
using System.Threading.Tasks;
using System.Linq;
+using System.IO;
+using Microsoft.Win32;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Core;
using NavisworksTransport.UI.WPF.Collections;
using NavisworksTransport.UI.WPF.Models;
using NavisworksTransport.UI.WPF.Commands;
using NavisworksTransport.Utils;
+using NavisworksTransport.Commands;
+using NavisworksTransport.PathPlanning;
namespace NavisworksTransport.UI.WPF.ViewModels
{
@@ -25,9 +29,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private PathPlanningManager _pathPlanningManager;
private readonly UIStateManager _uiStateManager;
+ private readonly PathDataManager _pathDataManager;
// 路径集合
- private ThreadSafeObservableCollection _pathRoutes;
+ private ObservableCollection _pathRoutes;
private PathRouteViewModel _selectedPathRoute;
private bool _isPathEditMode;
@@ -55,7 +60,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
#region 公共属性
- public ThreadSafeObservableCollection PathRoutes
+ public ObservableCollection PathRoutes
{
get => _pathRoutes;
set => SetProperty(ref _pathRoutes, value);
@@ -230,7 +235,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
public bool CanExecuteClearPath => SelectedPathRoute != null && SelectedPathRoute.Points.Count > 0;
- public bool CanExecuteExportPath => SelectedPathRoute != null && SelectedPathRoute.Points.Count > 0;
+ public bool CanExecuteExportPath => _pathPlanningManager?.Routes?.Count > 0;
public bool CanExecuteSaveAsPath => SelectedPathRoute != null && SelectedPathRoute.Points.Count > 0;
@@ -243,6 +248,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
try
{
_uiStateManager = UIStateManager.Instance;
+ _pathDataManager = new PathDataManager();
// 不在构造函数中创建PathPlanningManager,由外部设置
_pathPlanningManager = null;
@@ -254,7 +260,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
// PathPlanningManager将在外部设置,这里不需要检查
// 初始化集合
- PathRoutes = new ThreadSafeObservableCollection();
+ PathRoutes = new ObservableCollection();
// 初始化命令
InitializeCommands();
@@ -788,15 +794,99 @@ namespace NavisworksTransport.UI.WPF.ViewModels
#endregion
- #region 文件管理命令 - 待实现
+ #region 文件管理命令
private async Task ExecuteImportPathAsync()
{
await SafeExecuteAsync(async () =>
{
- // TODO: 实现文件导入逻辑
- await Task.CompletedTask;
- AutoPathStatus = "路径导入功能待实现";
+ try
+ {
+ // 打开文件选择对话框
+ var openFileDialog = new OpenFileDialog
+ {
+ Title = "导入路径文件",
+ Filter = "路径文件 (*.xml;*.json)|*.xml;*.json|XML文件 (*.xml)|*.xml|JSON文件 (*.json)|*.json|所有文件 (*.*)|*.*",
+ FilterIndex = 1,
+ CheckFileExists = true,
+ CheckPathExists = true
+ };
+
+ if (openFileDialog.ShowDialog() == true)
+ {
+ var filePath = openFileDialog.FileName;
+ var extension = Path.GetExtension(filePath).ToLower();
+
+ // 确定导入格式
+ var importFormat = extension == ".json" ? ExportFormat.Json : ExportFormat.Xml;
+
+ // 创建导入参数
+ var importParameters = new ImportPathParameters
+ {
+ FilePath = filePath,
+ ImportFormat = importFormat,
+ MergeWithExisting = true,
+ CreateBackup = true,
+ DuplicateHandling = DuplicateNameHandling.Rename,
+ ValidateImportedData = true,
+ AutoSelectFirstRoute = true,
+ Description = $"导入路径文件: {Path.GetFileName(filePath)}"
+ };
+
+ // 创建并执行导入命令
+ var importCommand = new ImportPathCommand(importParameters, _pathPlanningManager);
+ var result = await importCommand.ExecuteAsync();
+
+ if (result.IsSuccess)
+ {
+ // 更新UI状态
+ RefreshPathRoutes();
+
+ // 如果需要自动选择第一个导入的路径,通过专门的选择逻辑处理
+ if (importParameters.AutoSelectFirstRoute && PathRoutes.Count > 0)
+ {
+ var firstRoute = PathRoutes.FirstOrDefault();
+ if (firstRoute != null)
+ {
+ SelectedPathRoute = firstRoute;
+ LogManager.Info($"导入完成后自动选择路径: {firstRoute.Name}");
+ }
+ }
+
+ var importResult = (result as PathPlanningResult)?.Data;
+ if (importResult != null)
+ {
+ AutoPathStatus = $"✅ 导入成功: {importResult.ImportedCount}/{importResult.TotalInFile} 个路径";
+ if (importResult.FailedCount > 0)
+ {
+ AutoPathStatus += $" (失败 {importResult.FailedCount} 个)";
+ }
+ if (!string.IsNullOrEmpty(importResult.BackupFilePath))
+ {
+ LogManager.Info($"导入前备份已创建: {importResult.BackupFilePath}");
+ }
+ }
+ else
+ {
+ AutoPathStatus = $"✅ 路径导入完成: {Path.GetFileName(filePath)}";
+ }
+
+ PathFileStatus = "已导入";
+ }
+ else
+ {
+ AutoPathStatus = $"❌ 导入失败: {result.ErrorMessage}";
+ PathFileStatus = "导入失败";
+ LogManager.Error($"路径导入失败: {result.ErrorMessage}");
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"导入路径异常: {ex.Message}", ex);
+ AutoPathStatus = $"❌ 导入异常: {ex.Message}";
+ PathFileStatus = "导入异常";
+ }
}, "导入路径");
}
@@ -806,10 +896,76 @@ namespace NavisworksTransport.UI.WPF.ViewModels
await SafeExecuteAsync(async () =>
{
- // TODO: 实现文件导出逻辑
- await Task.CompletedTask;
- AutoPathStatus = $"导出路径: {SelectedPathRoute.Name}";
- PathFileStatus = "已保存";
+ try
+ {
+ // 打开文件保存对话框
+ var saveFileDialog = new SaveFileDialog
+ {
+ Title = "导出所有路径",
+ Filter = "XML文件 (*.xml)|*.xml|JSON文件 (*.json)|*.json|所有文件 (*.*)|*.*",
+ FilterIndex = 1,
+ FileName = $"路径导出_{DateTime.Now:yyyyMMdd_HHmmss}",
+ DefaultExt = "xml",
+ AddExtension = true
+ };
+
+ if (saveFileDialog.ShowDialog() == true)
+ {
+ var filePath = saveFileDialog.FileName;
+ var extension = Path.GetExtension(filePath).ToLower();
+
+ // 确定导出格式
+ var exportFormat = extension == ".json" ? ExportFormat.Json : ExportFormat.Xml;
+
+ // 创建导出参数 - 导出所有路径
+ var exportParameters = new ExportPathParameters
+ {
+ ExportAll = true,
+ OutputFilePath = filePath,
+ ExportFormat = exportFormat,
+ OverwriteExisting = true,
+ ValidateExportData = true,
+ GenerateReport = false,
+ Description = $"导出所有路径到: {Path.GetFileName(filePath)}"
+ };
+
+ // 创建并执行导出命令
+ var exportCommand = new ExportPathCommand(exportParameters, _pathPlanningManager);
+ var result = await exportCommand.ExecuteAsync();
+
+ if (result.IsSuccess)
+ {
+ var exportResult = (result as PathPlanningResult)?.Data;
+ if (exportResult != null)
+ {
+ AutoPathStatus = $"✅ 导出成功: {exportResult.ExportedCount} 个路径到 {Path.GetFileName(filePath)}";
+ if (exportResult.FailedCount > 0)
+ {
+ AutoPathStatus += $" (失败 {exportResult.FailedCount} 个)";
+ }
+ LogManager.Info($"导出完成,文件大小: {exportResult.FileSizeMB:F2} MB");
+ }
+ else
+ {
+ AutoPathStatus = $"✅ 路径导出完成: {Path.GetFileName(filePath)}";
+ }
+
+ PathFileStatus = "已导出";
+ }
+ else
+ {
+ AutoPathStatus = $"❌ 导出失败: {result.ErrorMessage}";
+ PathFileStatus = "导出失败";
+ LogManager.Error($"路径导出失败: {result.ErrorMessage}");
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"导出路径异常: {ex.Message}", ex);
+ AutoPathStatus = $"❌ 导出异常: {ex.Message}";
+ PathFileStatus = "导出异常";
+ }
}, "导出路径");
}
@@ -819,13 +975,141 @@ namespace NavisworksTransport.UI.WPF.ViewModels
await SafeExecuteAsync(async () =>
{
- // TODO: 实现另存为逻辑
- await Task.CompletedTask;
- AutoPathStatus = $"另存为路径: {SelectedPathRoute.Name}";
- PathFileStatus = "已保存";
+ try
+ {
+ // 打开文件保存对话框
+ var saveFileDialog = new SaveFileDialog
+ {
+ Title = $"另存为路径: {SelectedPathRoute?.Name}",
+ Filter = "XML文件 (*.xml)|*.xml|JSON文件 (*.json)|*.json|所有文件 (*.*)|*.*",
+ FilterIndex = 1,
+ FileName = SelectedPathRoute?.Name?.Replace(" ", "_") ?? "路径",
+ DefaultExt = "xml",
+ AddExtension = true
+ };
+
+ if (saveFileDialog.ShowDialog() == true)
+ {
+ var filePath = saveFileDialog.FileName;
+ var extension = Path.GetExtension(filePath).ToLower();
+
+ // 确定导出格式
+ var exportFormat = extension == ".json" ? ExportFormat.Json : ExportFormat.Xml;
+
+ // 查找当前选中路径对应的Core路径
+ var coreRoute = _pathPlanningManager.Routes.FirstOrDefault(r => r.Name == SelectedPathRoute.Name);
+ if (coreRoute != null)
+ {
+ // 创建导出参数 - 只导出当前选中的路径
+ var exportParameters = new ExportPathParameters
+ {
+ PathsToExport = new System.Collections.Generic.List { coreRoute },
+ OutputFilePath = filePath,
+ ExportFormat = exportFormat,
+ OverwriteExisting = true,
+ ValidateExportData = true,
+ GenerateReport = false,
+ Description = $"另存为路径: {SelectedPathRoute.Name}"
+ };
+
+ // 创建并执行导出命令
+ var exportCommand = new ExportPathCommand(exportParameters, _pathPlanningManager);
+ var result = await exportCommand.ExecuteAsync();
+
+ if (result.IsSuccess)
+ {
+ var exportResult = (result as PathPlanningResult)?.Data;
+ if (exportResult != null)
+ {
+ AutoPathStatus = $"✅ 另存为成功: {SelectedPathRoute.Name} -> {Path.GetFileName(filePath)}";
+ LogManager.Info($"另存为完成,文件大小: {exportResult.FileSizeMB:F2} MB");
+ }
+ else
+ {
+ AutoPathStatus = $"✅ 另存为完成: {Path.GetFileName(filePath)}";
+ }
+
+ PathFileStatus = "已另存为";
+ }
+ else
+ {
+ AutoPathStatus = $"❌ 另存为失败: {result.ErrorMessage}";
+ PathFileStatus = "另存为失败";
+ LogManager.Error($"另存为失败: {result.ErrorMessage}");
+ }
+ }
+ else
+ {
+ AutoPathStatus = $"❌ 找不到对应的Core路径: {SelectedPathRoute.Name}";
+ PathFileStatus = "另存为失败";
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"另存为路径异常: {ex.Message}", ex);
+ AutoPathStatus = $"❌ 另存为异常: {ex.Message}";
+ PathFileStatus = "另存为异常";
+ }
}, "另存为路径");
}
+ ///
+ /// 刷新路径集合显示
+ ///
+ private void RefreshPathRoutes()
+ {
+ try
+ {
+ if (_pathPlanningManager?.Routes != null)
+ {
+ // 清除现有的UI路径
+ PathRoutes.Clear();
+
+ // 重新加载所有路径
+ foreach (var coreRoute in _pathPlanningManager.Routes)
+ {
+ var pathViewModel = new PathRouteViewModel
+ {
+ Name = coreRoute.Name,
+ Description = coreRoute.Description,
+ IsActive = false
+ };
+
+ // 转换路径点
+ foreach (var corePoint in coreRoute.Points)
+ {
+ var wpfPoint = new PathPointViewModel
+ {
+ Name = corePoint.Name,
+ X = corePoint.X,
+ Y = corePoint.Y,
+ Z = corePoint.Z,
+ Type = corePoint.Type
+ };
+ pathViewModel.Points.Add(wpfPoint);
+ }
+
+ PathRoutes.Add(pathViewModel);
+ LogManager.Info($"RefreshPathRoutes: 添加路径ViewModel {coreRoute.Name} (Hash: {pathViewModel.GetHashCode()})");
+ }
+
+ LogManager.Info($"已刷新路径集合显示,共 {PathRoutes.Count} 个路径");
+
+ // 调试:列出所有PathRoutes中的路径名称和哈希码
+ for (int i = 0; i < PathRoutes.Count; i++)
+ {
+ var route = PathRoutes[i];
+ LogManager.Info($" PathRoutes[{i}]: {route.Name} (Hash: {route.GetHashCode()}, Points: {route.Points.Count})");
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"刷新路径集合失败: {ex.Message}", ex);
+ }
+ }
+
#endregion
#endregion
@@ -1267,6 +1551,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels
var pathViewModel = PathRoutes.FirstOrDefault(p => p.Name == e.Route.Name);
if (pathViewModel != null)
{
+ // 检查路径点数量是否已经正确,避免重复处理
+ if (pathViewModel.Points.Count == e.Route.Points.Count)
+ {
+ LogManager.Info($"路径点数量已正确({pathViewModel.Points.Count}),跳过重复更新");
+ return;
+ }
+
// 同步路径点数据
pathViewModel.Points.Clear();
foreach (var point in e.Route.Points)
@@ -1281,6 +1572,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels
};
pathViewModel.Points.Add(pointViewModel);
}
+ LogManager.Info($"已更新路径点列表,当前点数: {pathViewModel.Points.Count}");
+ }
+ else
+ {
+ LogManager.Warning($"未找到对应的PathViewModel: {e.Route.Name}");
}
}, "处理路径点列表更新事件");
}
@@ -1307,7 +1603,25 @@ namespace NavisworksTransport.UI.WPF.ViewModels
var pathViewModel = PathRoutes.FirstOrDefault(p => p.Name == e.NewRoute.Name);
if (pathViewModel != null)
{
- SelectedPathRoute = pathViewModel;
+ // 只在真的不同时才设置,避免重复触发
+ if (SelectedPathRoute != pathViewModel)
+ {
+ SelectedPathRoute = pathViewModel;
+ LogManager.Info($"UI已同步选择路径: {e.NewRoute.Name}");
+ }
+ }
+ else
+ {
+ LogManager.Warning($"OnCurrentRouteChanged: UI中未找到路径 {e.NewRoute.Name},可能UI还未刷新");
+ }
+ }
+ else
+ {
+ // 当前路径被设为null,清除UI选择
+ if (SelectedPathRoute != null)
+ {
+ SelectedPathRoute = null;
+ LogManager.Info("UI已清除路径选择");
}
}
}, "处理当前路径变更事件");
diff --git a/src/UI/WPF/Views/AboutDialog.xaml b/src/UI/WPF/Views/AboutDialog.xaml
new file mode 100644
index 0000000..63ddac3
--- /dev/null
+++ b/src/UI/WPF/Views/AboutDialog.xaml
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/UI/WPF/Views/AboutDialog.xaml.cs b/src/UI/WPF/Views/AboutDialog.xaml.cs
new file mode 100644
index 0000000..d3a5ade
--- /dev/null
+++ b/src/UI/WPF/Views/AboutDialog.xaml.cs
@@ -0,0 +1,24 @@
+using System.Windows;
+
+namespace NavisworksTransport.UI.WPF.Views
+{
+ ///
+ /// AboutDialog.xaml 的交互逻辑
+ /// 插件关于对话框,显示版本信息和开发者信息
+ ///
+ public partial class AboutDialog : Window
+ {
+ public AboutDialog()
+ {
+ InitializeComponent();
+ }
+
+ ///
+ /// 关闭按钮点击事件
+ ///
+ private void CloseButton_Click(object sender, RoutedEventArgs e)
+ {
+ this.Close();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/UI/WPF/Views/AnimationControlView.xaml b/src/UI/WPF/Views/AnimationControlView.xaml
index 0920df6..c608d8c 100644
--- a/src/UI/WPF/Views/AnimationControlView.xaml
+++ b/src/UI/WPF/Views/AnimationControlView.xaml
@@ -19,79 +19,35 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
d:DesignHeight="700" d:DesignWidth="480">
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
+
+
-
-
-
-
-
-
-
+
+
-
+
@@ -127,7 +83,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
-
+
@@ -220,7 +176,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
-
+
@@ -263,7 +219,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
-
+
-
-
+
@@ -338,7 +294,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
-
+
-
+
@@ -393,7 +349,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
-
+
@@ -417,16 +373,16 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
-
-
-
diff --git a/src/UI/WPF/Views/HelpDialog.xaml b/src/UI/WPF/Views/HelpDialog.xaml
new file mode 100644
index 0000000..b355329
--- /dev/null
+++ b/src/UI/WPF/Views/HelpDialog.xaml
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/UI/WPF/Views/HelpDialog.xaml.cs b/src/UI/WPF/Views/HelpDialog.xaml.cs
new file mode 100644
index 0000000..5b27513
--- /dev/null
+++ b/src/UI/WPF/Views/HelpDialog.xaml.cs
@@ -0,0 +1,24 @@
+using System.Windows;
+
+namespace NavisworksTransport.UI.WPF.Views
+{
+ ///
+ /// HelpDialog.xaml 的交互逻辑
+ /// 插件帮助对话框,显示详细的使用说明和操作指南
+ ///
+ public partial class HelpDialog : Window
+ {
+ public HelpDialog()
+ {
+ InitializeComponent();
+ }
+
+ ///
+ /// 关闭按钮点击事件
+ ///
+ private void CloseButton_Click(object sender, RoutedEventArgs e)
+ {
+ this.Close();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/UI/WPF/Views/LayerManagementView.xaml b/src/UI/WPF/Views/LayerManagementView.xaml
index f575650..307be4d 100644
--- a/src/UI/WPF/Views/LayerManagementView.xaml
+++ b/src/UI/WPF/Views/LayerManagementView.xaml
@@ -19,47 +19,22 @@ NavisworksTransport 分层管理页签视图 - 重构优化版本
d:DesignHeight="700" d:DesignWidth="420">
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
+
@@ -118,10 +93,10 @@ NavisworksTransport 分层管理页签视图 - 重构优化版本
-
-
+
+
-
+
@@ -152,7 +127,7 @@ NavisworksTransport 分层管理页签视图 - 重构优化版本
ItemsSource="{Binding DepthOptions}"
Margin="5,2" IsEnabled="{Binding IsNotProcessing}"/>
-
+
@@ -278,20 +243,6 @@ NavisworksTransport 分层管理页签视图 - 重构优化版本
FontWeight="SemiBold"
Foreground="#FF2B579A"
Margin="0,0,0,10"/>
-
-
-
-
-
-
-
@@ -317,7 +268,7 @@ NavisworksTransport 分层管理页签视图 - 重构优化版本
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
+
+
-
+
@@ -96,23 +51,10 @@ NavisworksTransport 类别设置页签视图 - 参考分层管理页签的设计
FontWeight="SemiBold"
Foreground="#FF2B579A"
Margin="0,0,0,5"/>
-
-
-
-
-
-
+
@@ -202,7 +144,7 @@ NavisworksTransport 类别设置页签视图 - 参考分层管理页签的设计
ToolTip="速度限制(米/秒)"/>
@@ -227,10 +169,10 @@ NavisworksTransport 类别设置页签视图 - 参考分层管理页签的设计
-
-
+
+
-
+
@@ -286,7 +228,7 @@ NavisworksTransport 类别设置页签视图 - 参考分层管理页签的设计
-
+
@@ -313,7 +255,7 @@ NavisworksTransport 类别设置页签视图 - 参考分层管理页签的设计
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
+
@@ -185,16 +132,16 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
-
+
-
+
-
-
@@ -229,22 +176,22 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
-
-
+
+
-
+
-
-
-