修改路径文件导入重复显示的问题

This commit is contained in:
tian 2025-08-20 19:24:06 +08:00
parent 3012e4752f
commit 9c83af59ca
22 changed files with 1770 additions and 480 deletions

View File

@ -184,6 +184,12 @@
<Compile Include="src\UI\WPF\Views\LayerManagementView.xaml.cs">
<DependentUpon>LayerManagementView.xaml</DependentUpon>
</Compile>
<Compile Include="src\UI\WPF\Views\HelpDialog.xaml.cs">
<DependentUpon>HelpDialog.xaml</DependentUpon>
</Compile>
<Compile Include="src\UI\WPF\Views\AboutDialog.xaml.cs">
<DependentUpon>AboutDialog.xaml</DependentUpon>
</Compile>
<!-- UI - WPF ViewModels -->
<Compile Include="src\UI\WPF\ViewModels\ViewModelBase.cs" />
@ -258,6 +264,20 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="src\UI\WPF\Views\HelpDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="src\UI\WPF\Views\AboutDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<!-- Shared Resource Dictionary -->
<Page Include="src\UI\WPF\Resources\NavisworksStyles.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WinFX\3.0\Microsoft.WinFX.targets" Condition="Exists('$(MSBuildExtensionsPath)\Microsoft\WinFX\3.0\Microsoft.WinFX.targets')" />

View File

@ -1,2 +1,31 @@
<!-- Core Animation System -->
<Compile Include="src\Core\Animation\PathAnimationManager.cs" />
<Compile Include="src\Core\Animation\PathAnimationManager.cs" /> <Page Include="src\UI\WPF\Views\AboutDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<!-- Shared Resource Dictionary -->
<Page Include="src\UI\WPF\Resources\NavisworksStyles.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup> <Page Include="src\UI\WPF\Views\AboutDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<!-- Shared Resource Dictionary -->
<Page Include="src\UI\WPF\Resources\NavisworksStyles.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup> <Page Include="src\UI\WPF\Views\AboutDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<!-- Shared Resource Dictionary -->
<Page Include="src\UI\WPF\Resources\NavisworksStyles.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WinFX\3.0\Microsoft.WinFX.targets" Condition="Exists('$(MSBuildExtensionsPath)\Microsoft\WinFX\3.0\Microsoft.WinFX.targets')" />

View File

@ -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<T> : ObservableCollection<T>
{
// 内部实现复杂的UI线程marshaling
private void OnCollectionChanged()
{
// 自定义的UI线程处理机制
_uiStateManager.QueueUIUpdate(() =>
{
base.OnCollectionChanged(...);
});
}
}
// ✅ 解决方案使用WPF标准集合
public ObservableCollection<PathRouteViewModel> PathRoutes { get; set; }
= new ObservableCollection<PathRouteViewModel>();
```
**核心冲突**
- `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<PathRouteViewModel> PathRoutes { get; private set; }
= new ObservableCollection<PathRouteViewModel>();
}
public class PathRouteViewModel : ViewModelBase
{
// 路径点集合也使用标准集合
public ObservableCollection<PathPointViewModel> Points { get; private set; }
= new ObservableCollection<PathPointViewModel>();
// 简化初始化:同步完成,无异步复杂性
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<T> : ObservableCollection<T>
{
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<T> Items { get; private set; } = new ObservableCollection<T>();
```
#### 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<ItemViewModel> Items { get; private set; }
= new ObservableCollection<ItemViewModel>();
// ✅ 后台数据处理:可以使用线程安全集合
private readonly ConcurrentBag<ProcessingItem> _processingQueue
= new ConcurrentBag<ProcessingItem>();
// ✅ UI更新时统一在UI线程操作
public async Task UpdateUI(List<ItemData> 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. 线程安全实践经验总结
### 问题描述

View File

@ -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<ItemType> Items { get; private set; }
= new ThreadSafeObservableCollection<ItemType>();
// ✅ 修改后
public ObservableCollection<ItemType> Items { get; private set; }
= new ObservableCollection<ItemType>();
```
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<T> UIBoundItems { get; private set; }
= new ObservableCollection<T>();
// ✅ 后台数据处理场景
private readonly ConcurrentBag<T> _processingQueue
= new ConcurrentBag<T>();
// ✅ UI更新统一处理
public async Task UpdateUI(List<T> 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<LogisticsModel>)
- AvailableCategories (ThreadSafeObservableCollection<string>)
- AvailableFrameRates (ThreadSafeObservableCollection<int>)
```
**验证项目**:
- [ ] 物流模型显示正常
- [ ] 分类选择功能正常
- [ ] 帧率设置功能正常
- [ ] 无UI重复显示问题
### 第二批迁移: LayerManagementViewModel
```csharp
// 需要迁移的属性:
- AvailableAttributes (ThreadSafeObservableCollection<string>)
- DepthOptions (ThreadSafeObservableCollection<string>)
- SplitStrategies (ThreadSafeObservableCollection<string>)
- SplitPreviewResults (ThreadSafeObservableCollection<SplitPreviewItem>)
```
**验证项目**:
- [ ] 图层管理界面显示正常
- [ ] 属性选择功能正常
- [ ] 模型分割预览功能正常
- [ ] 分割策略选择正常
### 第三批迁移: ModelSettingsViewModel
```csharp
// 需要迁移的属性:
- AvailableCategories (ThreadSafeObservableCollection<string>)
- PriorityLevels (ThreadSafeObservableCollection<int>)
- LogisticsModels (ThreadSafeObservableCollection<LogisticsModel>)
```
**验证项目**:
- [ ] 模型设置界面显示正常
- [ ] 分类设置功能正常
- [ ] 优先级设置功能正常
### 第四批迁移: 其他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显示功能正常
- [ ] 无重复数据显示
- [ ] 性能无明显退化

View File

@ -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, "路径导入完成");

View File

@ -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) =>

View File

@ -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;
}

View File

@ -1,3 +1,15 @@
<!--
NavisworksTransport 主控制面板 - 采用与其他视图一致的Navisworks 2026风格
功能说明:
1. 分层管理:模型分层控制和可见性管理
2. 类别设置:物流类别设置和属性管理
3. 路径编辑3D路径规划和编辑功能
4. 检测动画:路径动画生成和碰撞检测
5. 系统管理:日志管理、插件设置和性能监控
设计原则与Navisworks 2026风格一致480像素宽度现代化UI布局
-->
<UserControl x:Class="NavisworksTransport.UI.WPF.LogisticsControlPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@ -6,6 +18,16 @@
xmlns:views="clr-namespace:NavisworksTransport.UI.WPF.Views"
mc:Ignorable="d"
d:DesignHeight="700" d:DesignWidth="480">
<UserControl.Resources>
<!-- 引用共享的Navisworks 2026样式资源 -->
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/NavisworksTransportPlugin;component/src/UI/WPF/Resources/NavisworksStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
@ -13,32 +35,60 @@
</Grid.RowDefinitions>
<!-- 主内容区域 -->
<TabControl Grid.Row="0" Name="MainTabControl" Margin="5">
<TabItem Header="分层管理" Name="LayerManagementTab">
<ContentControl x:Name="LayerManagementContent"/>
</TabItem>
<TabItem Header="类别设置" Name="ModelSettingsTab">
<ContentControl x:Name="ModelSettingsContent"/>
</TabItem>
<TabItem Header="路径编辑" Name="PathEditingTab">
<views:PathEditingView x:Name="PathEditingView"/>
</TabItem>
<TabItem Header="检测动画" Name="AnimationControlTab">
<views:AnimationControlView x:Name="AnimationControlView"/>
</TabItem>
<TabItem Header="系统管理" Name="SystemManagementTab">
<views:SystemManagementView x:Name="SystemManagementView"/>
</TabItem>
</TabControl>
<TabControl Grid.Row="0"
Name="MainTabControl"
Style="{StaticResource NavisworksTabControlStyle}"
Margin="10,10,10,5">
<TabItem Header="分层管理" Name="LayerManagementTab" Style="{StaticResource NavisworksTabItemStyle}">
<Border Background="White" CornerRadius="0">
<ContentControl x:Name="LayerManagementContent" Margin="0"/>
</Border>
</TabItem>
<TabItem Header="类别设置" Name="ModelSettingsTab" Style="{StaticResource NavisworksTabItemStyle}">
<Border Background="White" CornerRadius="0">
<ContentControl x:Name="ModelSettingsContent" Margin="0"/>
</Border>
</TabItem>
<TabItem Header="路径编辑" Name="PathEditingTab" Style="{StaticResource NavisworksTabItemStyle}">
<Border Background="White" CornerRadius="0">
<views:PathEditingView x:Name="PathEditingView" Margin="0"/>
</Border>
</TabItem>
<TabItem Header="检测动画" Name="AnimationControlTab" Style="{StaticResource NavisworksTabItemStyle}">
<Border Background="White" CornerRadius="0">
<views:AnimationControlView x:Name="AnimationControlView" Margin="0"/>
</Border>
</TabItem>
<TabItem Header="系统管理" Name="SystemManagementTab" Style="{StaticResource NavisworksTabItemStyle}">
<Border Background="White" CornerRadius="0">
<views:SystemManagementView x:Name="SystemManagementView" Margin="0"/>
</Border>
</TabItem>
</TabControl>
<!-- 底部操作栏 -->
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right" Margin="10">
<Button Content="帮助" Click="HelpButton_Click" Margin="0,0,10,0"/>
<Button Content="关于" Click="AboutButton_Click" Margin="0,0,10,0"/>
</StackPanel>
<Border Grid.Row="1"
BorderBrush="#FFD4E7FF"
BorderThickness="1"
CornerRadius="0"
Background="#FFF8FBFF"
Margin="10,5,10,10"
Padding="12,8">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Right">
<Button Content="帮助"
Click="HelpButton_Click"
Style="{StaticResource SecondaryButtonStyle}"
ToolTip="查看插件使用说明和操作指南"/>
<Button Content="关于"
Click="AboutButton_Click"
Style="{StaticResource SecondaryButtonStyle}"
ToolTip="查看插件版本信息和开发者信息"/>
</StackPanel>
</Border>
</Grid>
</UserControl>

View File

@ -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();
}, "显示关于");
}

View File

@ -145,7 +145,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
#region
private string _name;
private ThreadSafeObservableCollection<PathPointViewModel> _points;
private ObservableCollection<PathPointViewModel> _points;
private bool _isActive;
private string _description;
private bool _isOptimal;
@ -181,9 +181,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
/// <summary>
/// 路径点集合(线程安全)
/// 路径点集合
/// </summary>
public ThreadSafeObservableCollection<PathPointViewModel> Points
public ObservableCollection<PathPointViewModel> 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<PathPointViewModel>();
// 初始化点集合
Points = new ObservableCollection<PathPointViewModel>();
}
/// <summary>
/// 异步初始化方法
/// 完成初始化
/// </summary>
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);
}
}
/// <summary>
/// 异步初始化方法(保留用于向后兼容)
/// </summary>
/// <returns>异步任务</returns>
[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; // 现在初始化已经在构造函数中同步完成
}
/// <summary>
@ -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();

View File

@ -0,0 +1,195 @@
<!--
NavisworksTransport 共享样式资源字典 - Navisworks 2026风格
功能说明:
1. 统一管理所有UI组件的样式定义
2. 保持与Navisworks 2026风格一致的设计
3. 简化样式维护和修改
设计原则:蓝色主题配色,现代化布局,统一字体
-->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Navisworks 2026 主要颜色定义 -->
<Color x:Key="NavisworksPrimaryBlue">#FF2B579A</Color>
<Color x:Key="NavisworksSecondaryBlue">#FF4472C4</Color>
<Color x:Key="NavisworksLightBlue">#FFD4E7FF</Color>
<Color x:Key="NavisworksBackgroundBlue">#FFF8FBFF</Color>
<Color x:Key="NavisworksButtonBlue">#FFE7F1FF</Color>
<Color x:Key="NavisworksTextGray">#FF666666</Color>
<Color x:Key="NavisworksDarkGray">#FF333333</Color>
<!-- Navisworks 2026 画刷定义 -->
<SolidColorBrush x:Key="NavisworksPrimaryBrush" Color="{StaticResource NavisworksPrimaryBlue}"/>
<SolidColorBrush x:Key="NavisworksSecondaryBrush" Color="{StaticResource NavisworksSecondaryBlue}"/>
<SolidColorBrush x:Key="NavisworksLightBrush" Color="{StaticResource NavisworksLightBlue}"/>
<SolidColorBrush x:Key="NavisworksBackgroundBrush" Color="{StaticResource NavisworksBackgroundBlue}"/>
<SolidColorBrush x:Key="NavisworksButtonBrush" Color="{StaticResource NavisworksButtonBlue}"/>
<SolidColorBrush x:Key="NavisworksTextBrush" Color="{StaticResource NavisworksTextGray}"/>
<SolidColorBrush x:Key="NavisworksDarkBrush" Color="{StaticResource NavisworksDarkGray}"/>
<!-- 区域标题样式 -->
<Style x:Key="SectionHeaderStyle" TargetType="Label">
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="{StaticResource NavisworksPrimaryBrush}"/>
<Setter Property="Padding" Value="0,5,0,2"/>
</Style>
<!-- 主要操作按钮样式 -->
<Style x:Key="ActionButtonStyle" TargetType="Button">
<Setter Property="Background" Value="{StaticResource NavisworksSecondaryBrush}"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderBrush" Value="{StaticResource NavisworksPrimaryBrush}"/>
<Setter Property="Padding" Value="10,5"/>
<Setter Property="Margin" Value="0,0,10,0"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="MinWidth" Value="60"/>
<Setter Property="Height" Value="28"/>
</Style>
<!-- 次要操作按钮样式 -->
<Style x:Key="SecondaryButtonStyle" TargetType="Button">
<Setter Property="Background" Value="{StaticResource NavisworksButtonBrush}"/>
<Setter Property="Foreground" Value="{StaticResource NavisworksPrimaryBrush}"/>
<Setter Property="BorderBrush" Value="{StaticResource NavisworksSecondaryBrush}"/>
<Setter Property="Padding" Value="8,4"/>
<Setter Property="Margin" Value="0,0,8,0"/>
<Setter Property="MinWidth" Value="60"/>
<Setter Property="Height" Value="28"/>
</Style>
<!-- 状态文本样式 -->
<Style x:Key="StatusTextStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="10"/>
<Setter Property="Foreground" Value="{StaticResource NavisworksTextBrush}"/>
<Setter Property="TextWrapping" Value="Wrap"/>
</Style>
<!-- 参数标签样式 -->
<Style x:Key="ParameterLabelStyle" TargetType="Label">
<Setter Property="Width" Value="80"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Padding" Value="0,0,5,0"/>
</Style>
<!-- 参数输入框样式 -->
<Style x:Key="ParameterInputStyle" TargetType="TextBox">
<Setter Property="Width" Value="80"/>
<Setter Property="Margin" Value="5,2"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
<!-- 单位标签样式 -->
<Style x:Key="UnitLabelStyle" TargetType="Label">
<Setter Property="Width" Value="30"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Padding" Value="2,0,0,0"/>
<Setter Property="FontSize" Value="10"/>
<Setter Property="Foreground" Value="{StaticResource NavisworksTextBrush}"/>
</Style>
<!-- 只读文本框样式 -->
<Style x:Key="ReadOnlyTextBoxStyle" TargetType="TextBox">
<Setter Property="IsReadOnly" Value="True"/>
<Setter Property="Background" Value="#FFF5F5F5"/>
<Setter Property="BorderBrush" Value="#FFCCCCCC"/>
<Setter Property="Padding" Value="5,3"/>
<Setter Property="Margin" Value="5,2"/>
</Style>
<!-- TabControl样式定义 -->
<Style x:Key="NavisworksTabControlStyle" TargetType="TabControl">
<Setter Property="Background" Value="White"/>
<Setter Property="BorderBrush" Value="{StaticResource NavisworksLightBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
</Style>
<!-- TabItem样式定义 -->
<Style x:Key="NavisworksTabItemStyle" TargetType="TabItem">
<Setter Property="Background" Value="{StaticResource NavisworksBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{StaticResource NavisworksLightBrush}"/>
<Setter Property="BorderThickness" Value="1,1,1,0"/>
<Setter Property="Margin" Value="0,0,2,0"/>
<Setter Property="Padding" Value="12,6"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="Foreground" Value="{StaticResource NavisworksPrimaryBrush}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<Border Name="Border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="0">
<ContentPresenter ContentSource="Header"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="White"/>
<Setter Property="Foreground" Value="{StaticResource NavisworksPrimaryBrush}"/>
<Setter Property="FontWeight" Value="Normal"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Border" Property="Background" Value="{StaticResource NavisworksButtonBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- 对话框专用样式 -->
<Style x:Key="DialogTitleStyle" TargetType="Label">
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="Foreground" Value="{StaticResource NavisworksPrimaryBrush}"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="Padding" Value="0,10,0,8"/>
</Style>
<Style x:Key="DialogVersionStyle" TargetType="Label">
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Foreground" Value="{StaticResource NavisworksSecondaryBrush}"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="Padding" Value="0,5,0,5"/>
</Style>
<Style x:Key="DialogInfoLabelStyle" TargetType="Label">
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="FontSize" Value="11"/>
<Setter Property="Foreground" Value="{StaticResource NavisworksPrimaryBrush}"/>
<Setter Property="Width" Value="80"/>
<Setter Property="Padding" Value="0,4"/>
</Style>
<Style x:Key="DialogInfoTextStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="11"/>
<Setter Property="Foreground" Value="{StaticResource NavisworksDarkBrush}"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="Margin" Value="10,0"/>
</Style>
<Style x:Key="DialogDescriptionStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="11"/>
<Setter Property="Foreground" Value="{StaticResource NavisworksTextBrush}"/>
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="TextAlignment" Value="Center"/>
<Setter Property="LineHeight" Value="16"/>
<Setter Property="Margin" Value="20,15"/>
</Style>
<Style x:Key="DialogContentTextStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="11"/>
<Setter Property="Foreground" Value="{StaticResource NavisworksDarkBrush}"/>
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="LineHeight" Value="16"/>
<Setter Property="Margin" Value="10,2,0,4"/>
</Style>
</ResourceDictionary>

View File

@ -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<PathRouteViewModel> _pathRoutes;
private ObservableCollection<PathRouteViewModel> _pathRoutes;
private PathRouteViewModel _selectedPathRoute;
private bool _isPathEditMode;
@ -55,7 +60,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
#region
public ThreadSafeObservableCollection<PathRouteViewModel> PathRoutes
public ObservableCollection<PathRouteViewModel> 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<PathRouteViewModel>();
PathRoutes = new ObservableCollection<PathRouteViewModel>();
// 初始化命令
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<ImportPathResult>)?.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<ExportPathResult>)?.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<PathRoute> { 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<ExportPathResult>)?.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 = "另存为异常";
}
}, "另存为路径");
}
/// <summary>
/// 刷新路径集合显示
/// </summary>
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已清除路径选择");
}
}
}, "处理当前路径变更事件");

View File

@ -0,0 +1,122 @@
<!--
NavisworksTransport 关于对话框 - 采用与主界面一致的Navisworks 2026风格
功能说明:
1. 显示插件版本信息和开发者信息
2. 提供技术支持和联系方式
3. 与主界面保持一致的视觉风格
设计原则:使用统一的蓝色主题和样式规范
-->
<Window x:Class="NavisworksTransport.UI.WPF.Views.AboutDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
Title="关于插件"
Height="400"
Width="500"
ResizeMode="NoResize"
WindowStartupLocation="CenterOwner">
<Window.Resources>
<!-- 引用共享的Navisworks 2026样式资源 -->
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/NavisworksTransportPlugin;component/src/UI/WPF/Resources/NavisworksStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 主内容区域 -->
<Border Grid.Row="0"
BorderBrush="#FFD4E7FF"
BorderThickness="1"
CornerRadius="0"
Background="White"
Margin="15,15,15,10">
<StackPanel Margin="20">
<!-- 插件标题和版本 -->
<Label Content="NavisworksTransport" Style="{StaticResource TitleStyle}"/>
<Label Content="物流路径规划插件 v1.0" Style="{StaticResource VersionStyle}"/>
<!-- 分隔线 -->
<Border Height="1"
Background="#FFD4E7FF"
Margin="0,15,0,20"/>
<!-- 基本信息 -->
<Grid Margin="0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="适用版本:" Style="{StaticResource InfoLabelStyle}"/>
<TextBlock Grid.Row="0" Grid.Column="1" Text="Autodesk Navisworks Manage 2026" Style="{StaticResource InfoTextStyle}"/>
<Label Grid.Row="1" Grid.Column="0" Content="版本号:" Style="{StaticResource InfoLabelStyle}"/>
<TextBlock Grid.Row="1" Grid.Column="1" Text="1.0.0" Style="{StaticResource InfoTextStyle}"/>
<Label Grid.Row="2" Grid.Column="0" Content="发布日期:" Style="{StaticResource InfoLabelStyle}"/>
<TextBlock Grid.Row="2" Grid.Column="1" Text="2024年8月" Style="{StaticResource InfoTextStyle}"/>
<Label Grid.Row="3" Grid.Column="0" Content="开发语言:" Style="{StaticResource InfoLabelStyle}"/>
<TextBlock Grid.Row="3" Grid.Column="1" Text="C# .NET Framework 4.8" Style="{StaticResource InfoTextStyle}"/>
<Label Grid.Row="4" Grid.Column="0" Content="UI框架:" Style="{StaticResource InfoLabelStyle}"/>
<TextBlock Grid.Row="4" Grid.Column="1" Text="WPF + MVVM" Style="{StaticResource InfoTextStyle}"/>
</Grid>
<!-- 功能描述 -->
<TextBlock Text="专为Navisworks 2026设计的物流路径规划插件。支持3D路径规划、A*寻路算法、动画生成、碰撞检测等功能。通过直观的用户界面,帮助用户在建筑信息模型中进行高效的物流运输规划和冲突检测。"
Style="{StaticResource DescriptionStyle}"/>
<!-- 主要特性 -->
<TextBlock Style="{StaticResource DescriptionStyle}" Margin="20,10">
<Run Text="主要特性:" FontWeight="Medium" Foreground="#FF2B579A"/>
<LineBreak/>
<Run Text="• 智能路径规划与A*算法优化"/>
<LineBreak/>
<Run Text="• 实时碰撞检测与冲突分析"/>
<LineBreak/>
<Run Text="• 流畅的3D动画演示"/>
<LineBreak/>
<Run Text="• 完整的物流类别管理系统"/>
</TextBlock>
</StackPanel>
</Border>
<!-- 底部按钮 -->
<Border Grid.Row="1"
BorderBrush="#FFD4E7FF"
BorderThickness="1"
CornerRadius="0"
Background="#FFF8FBFF"
Margin="15,0,15,15"
Padding="15,10">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Right">
<Button Content="关闭"
Click="CloseButton_Click"
Style="{StaticResource ActionButtonStyle}"/>
</StackPanel>
</Border>
</Grid>
</Window>

View File

@ -0,0 +1,24 @@
using System.Windows;
namespace NavisworksTransport.UI.WPF.Views
{
/// <summary>
/// AboutDialog.xaml 的交互逻辑
/// 插件关于对话框,显示版本信息和开发者信息
/// </summary>
public partial class AboutDialog : Window
{
public AboutDialog()
{
InitializeComponent();
}
/// <summary>
/// 关闭按钮点击事件
/// </summary>
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
}
}

View File

@ -19,79 +19,35 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
d:DesignHeight="700" d:DesignWidth="480">
<UserControl.Resources>
<!-- 转换器资源 -->
<converters:BoolToVisibilityConverter x:Key="BoolToVisConverter"/>
<!-- Navisworks 2026 风格样式定义 -->
<Style x:Key="SectionHeaderStyle" TargetType="Label">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="#FF2B579A"/>
<Setter Property="Padding" Value="0,5,0,2"/>
</Style>
<Style x:Key="ActionButtonStyle" TargetType="Button">
<Setter Property="Background" Value="#FF4472C4"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderBrush" Value="#FF2B579A"/>
<Setter Property="Padding" Value="10,5"/>
<Setter Property="Margin" Value="0,0,10,0"/>
<Setter Property="FontWeight" Value="SemiBold"/>
</Style>
<Style x:Key="SecondaryButtonStyle" TargetType="Button">
<Setter Property="Background" Value="#FFE7F1FF"/>
<Setter Property="Foreground" Value="#FF2B579A"/>
<Setter Property="BorderBrush" Value="#FF4472C4"/>
<Setter Property="Padding" Value="8,4"/>
<Setter Property="Margin" Value="0,0,8,0"/>
</Style>
<Style x:Key="StatusTextStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="10"/>
<Setter Property="Foreground" Value="#FF666666"/>
<Setter Property="TextWrapping" Value="Wrap"/>
</Style>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/NavisworksTransportPlugin;component/src/UI/WPF/Resources/NavisworksStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
<!-- 转换器资源 -->
<converters:BoolToVisibilityConverter x:Key="BoolToVisConverter"/>
<Style x:Key="ParameterLabelStyle" TargetType="Label">
<Setter Property="Width" Value="80"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Padding" Value="0,0,5,0"/>
</Style>
<!-- 动画控制页面特有的样式 -->
<Style x:Key="ProgressBarStyle" TargetType="ProgressBar">
<Setter Property="Height" Value="20"/>
<Setter Property="Foreground" Value="{StaticResource NavisworksSecondaryBrush}"/>
<Setter Property="Background" Value="{StaticResource NavisworksButtonBrush}"/>
<Setter Property="BorderBrush" Value="{StaticResource NavisworksPrimaryBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
</Style>
<Style x:Key="ParameterInputStyle" TargetType="TextBox">
<Setter Property="Width" Value="80"/>
<Setter Property="Margin" Value="5,2"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
<Style x:Key="UnitLabelStyle" TargetType="Label">
<Setter Property="Width" Value="30"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Padding" Value="2,0,0,0"/>
<Setter Property="FontSize" Value="10"/>
<Setter Property="Foreground" Value="#FF666666"/>
</Style>
<Style x:Key="ProgressBarStyle" TargetType="ProgressBar">
<Setter Property="Height" Value="20"/>
<Setter Property="Foreground" Value="#FF4472C4"/>
<Setter Property="Background" Value="#FFE7F1FF"/>
<Setter Property="BorderBrush" Value="#FF2B579A"/>
<Setter Property="BorderThickness" Value="1"/>
</Style>
<Style x:Key="SliderStyle" TargetType="Slider">
<Setter Property="Foreground" Value="#FF4472C4"/>
<Setter Property="Height" Value="20"/>
</Style>
<Style x:Key="SliderStyle" TargetType="Slider">
<Setter Property="Foreground" Value="{StaticResource NavisworksSecondaryBrush}"/>
<Setter Property="Height" Value="20"/>
</Style>
</ResourceDictionary>
</UserControl.Resources>
<ScrollViewer VerticalScrollBarVisibility="Auto" Padding="10">
<StackPanel>
<!-- 区域1: 动画参数设置 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,15" Padding="12">
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Label Content="动画参数设置" Style="{StaticResource SectionHeaderStyle}"/>
@ -127,7 +83,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
</Border>
<!-- 区域2: 碰撞检测参数 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,15" Padding="12">
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Label Content="碰撞检测参数" Style="{StaticResource SectionHeaderStyle}"/>
@ -220,7 +176,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
</Border>
<!-- 区域3: 生成动画 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,15" Padding="12">
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Label Content="生成动画" Style="{StaticResource SectionHeaderStyle}"/>
@ -263,7 +219,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="动路径:" Style="{StaticResource ParameterLabelStyle}" Width="80"/>
<Label Grid.Column="0" Content="动路径:" Style="{StaticResource ParameterLabelStyle}" Width="80"/>
<TextBlock Grid.Column="1"
Text="{Binding CurrentPathRoute.Name, StringFormat='当前路径: {0}', TargetNullValue='当前路径: 未选择'}"
VerticalAlignment="Center"
@ -295,7 +251,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
</StackPanel>
<!-- 生成状态提示 -->
<TextBlock Text="提示:需要同时选择移动物体和动路径才能生成动画"
<TextBlock Text="提示:需要同时选择移动物体和动路径才能生成动画"
Style="{StaticResource StatusTextStyle}"
Foreground="#FF666666"
Margin="0,5,0,0"
@ -304,7 +260,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
</Border>
<!-- 区域4: 播放控制 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,15" Padding="12">
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Label Content="播放控制" Style="{StaticResource SectionHeaderStyle}"/>
@ -338,7 +294,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="进度:" Width="50" VerticalAlignment="Center"/>
<Label Grid.Column="0" Content="播放进度:" Width="50" VerticalAlignment="Center"/>
<ProgressBar Grid.Column="1"
Value="{Binding AnimationProgress}"
Style="{StaticResource ProgressBarStyle}"
@ -363,7 +319,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
</Border>
<!-- 区域5: 碰撞检测 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,15" Padding="12">
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Label Content="碰撞检测" Style="{StaticResource SectionHeaderStyle}"/>
@ -393,7 +349,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
</Border>
<!-- 区域6: 动画预览和操作指南 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,0" Padding="12">
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,0" Padding="12">
<StackPanel>
<Label Content="动画预览与操作指南" Style="{StaticResource SectionHeaderStyle}"/>
@ -417,16 +373,16 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
<!-- 操作提示 -->
<StackPanel Margin="0,5,0,0">
<TextBlock Text="• 确保已在路径编辑页签中选择有效的路径进行动画"
<TextBlock Text="• 确保已在路径编辑页签中选择有效的路径"
Style="{StaticResource StatusTextStyle}"
Margin="0,2"/>
<TextBlock Text="• 动画将沿着当前选中的路径创建相机跟随视点序列"
<TextBlock Text="• 动画将沿着当前选中的路径创建"
Style="{StaticResource StatusTextStyle}"
Margin="0,2"/>
<TextBlock Text="• 碰撞检测会在路径上模拟运输过程中的冲突检测"
Style="{StaticResource StatusTextStyle}"
Margin="0,2"/>
<TextBlock Text="• 动画播放后可在Navisworks视点管理器中手动控制播放"
<TextBlock Text="• 碰撞检测后可在ClashDetective插件中查看碰撞结果"
Style="{StaticResource StatusTextStyle}"
Margin="0,2"/>
</StackPanel>

View File

@ -0,0 +1,145 @@
<!--
NavisworksTransport 帮助对话框 - 采用与主界面一致的Navisworks 2026风格
功能说明:
1. 显示插件详细使用说明
2. 提供操作指南和功能介绍
3. 与主界面保持一致的视觉风格
设计原则:使用统一的蓝色主题和样式规范
-->
<Window x:Class="NavisworksTransport.UI.WPF.Views.HelpDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
Title="插件帮助"
Height="500"
Width="650"
ResizeMode="NoResize"
WindowStartupLocation="CenterOwner">
<Window.Resources>
<!-- 引用共享的Navisworks 2026样式资源 -->
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/NavisworksTransportPlugin;component/src/UI/WPF/Resources/NavisworksStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
<!-- 帮助对话框专用样式 -->
<Style x:Key="SubSectionHeaderStyle" TargetType="Label">
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="{StaticResource NavisworksSecondaryBrush}"/>
<Setter Property="Padding" Value="0,6,0,2"/>
</Style>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 主内容区域 -->
<Border Grid.Row="0"
BorderBrush="#FFD4E7FF"
BorderThickness="1"
CornerRadius="0"
Background="White"
Margin="15,15,15,10">
<ScrollViewer VerticalScrollBarVisibility="Auto"
Padding="15">
<StackPanel>
<Label Content="NavisworksTransport 物流路径规划插件"
Style="{StaticResource SectionHeaderStyle}"
FontSize="16"
HorizontalAlignment="Center"
Margin="0,0,0,10"/>
<!-- 分层管理 -->
<Label Content="1. 分层管理" Style="{StaticResource SubSectionHeaderStyle}"/>
<TextBlock Text="• 控制模型各层级的可见性和透明度"
Style="{StaticResource DialogContentTextStyle}"/>
<TextBlock Text="• 管理物流相关模型组件的显示状态"
Style="{StaticResource DialogContentTextStyle}"/>
<TextBlock Text="• 提供快速隐藏/显示功能,优化建模环境"
Style="{StaticResource DialogContentTextStyle}"/>
<!-- 类别设置 -->
<Label Content="2. 类别设置" Style="{StaticResource SubSectionHeaderStyle}"/>
<TextBlock Text="• 设置模型元素的物流类别属性(门、电梯、楼梯、通道等)"
Style="{StaticResource DialogContentTextStyle}"/>
<TextBlock Text="• 管理可通行性和障碍物标记"
Style="{StaticResource DialogContentTextStyle}"/>
<TextBlock Text="• 配置装卸区、停车区、检查点等物流功能区域"
Style="{StaticResource DialogContentTextStyle}"/>
<!-- 路径编辑 -->
<Label Content="3. 路径编辑" Style="{StaticResource SubSectionHeaderStyle}"/>
<TextBlock Text="• 自动路径规划:设置起终点,输入车辆尺寸,自动生成最优路径"
Style="{StaticResource DialogContentTextStyle}"/>
<TextBlock Text="• 手动路径创建在3D视图中点击创建自定义路径"
Style="{StaticResource DialogContentTextStyle}"/>
<TextBlock Text="• 路径管理:新建、删除、重命名、导入导出路径文件"
Style="{StaticResource DialogContentTextStyle}"/>
<TextBlock Text="• 路径编辑:添加、删除、调整路径点位置"
Style="{StaticResource DialogContentTextStyle}"/>
<!-- 检测动画 -->
<Label Content="4. 检测动画" Style="{StaticResource SubSectionHeaderStyle}"/>
<TextBlock Text="• 生成沿路径的运输动画,支持自定义速度和帧率"
Style="{StaticResource DialogContentTextStyle}"/>
<TextBlock Text="• 运行碰撞检测,识别路径中的潜在冲突"
Style="{StaticResource DialogContentTextStyle}"/>
<TextBlock Text="• 播放控制:开始、暂停、停止动画"
Style="{StaticResource DialogContentTextStyle}"/>
<TextBlock Text="• 查看详细的碰撞检测报告"
Style="{StaticResource DialogContentTextStyle}"/>
<!-- 系统管理 -->
<Label Content="5. 系统管理" Style="{StaticResource SubSectionHeaderStyle}"/>
<TextBlock Text="• 日志管理:查看、清空、导出系统运行日志"
Style="{StaticResource DialogContentTextStyle}"/>
<TextBlock Text="• 插件设置:配置选项和功能开关"
Style="{StaticResource DialogContentTextStyle}"/>
<TextBlock Text="• 系统信息:查看插件版本、内存使用和性能状态"
Style="{StaticResource DialogContentTextStyle}"/>
<TextBlock Text="• 性能监控:生成性能报告和优化建议"
Style="{StaticResource DialogContentTextStyle}"/>
<!-- 使用提示 -->
<Label Content="使用提示" Style="{StaticResource SubSectionHeaderStyle}" Margin="0,15,0,5"/>
<TextBlock Text="1. 首次使用建议先在类别设置中标记物流相关的模型元素"
Style="{StaticResource DialogContentTextStyle}"/>
<TextBlock Text="2. 路径规划时需要确保起终点设在可通行的模型上"
Style="{StaticResource DialogContentTextStyle}"/>
<TextBlock Text="3. 自动路径规划需要合理设置车辆尺寸和安全间隙"
Style="{StaticResource DialogContentTextStyle}"/>
<TextBlock Text="4. 碰撞检测结果可在ClashDetective插件中查看详情"
Style="{StaticResource DialogContentTextStyle}"/>
</StackPanel>
</ScrollViewer>
</Border>
<!-- 底部按钮 -->
<Border Grid.Row="1"
BorderBrush="#FFD4E7FF"
BorderThickness="1"
CornerRadius="0"
Background="#FFF8FBFF"
Margin="15,0,15,15"
Padding="15,10">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Right">
<Button Content="关闭"
Click="CloseButton_Click"
Style="{StaticResource ActionButtonStyle}"/>
</StackPanel>
</Border>
</Grid>
</Window>

View File

@ -0,0 +1,24 @@
using System.Windows;
namespace NavisworksTransport.UI.WPF.Views
{
/// <summary>
/// HelpDialog.xaml 的交互逻辑
/// 插件帮助对话框,显示详细的使用说明和操作指南
/// </summary>
public partial class HelpDialog : Window
{
public HelpDialog()
{
InitializeComponent();
}
/// <summary>
/// 关闭按钮点击事件
/// </summary>
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
}
}

View File

@ -19,47 +19,22 @@ NavisworksTransport 分层管理页签视图 - 重构优化版本
d:DesignHeight="700" d:DesignWidth="420">
<UserControl.Resources>
<!-- 转换器资源 -->
<converters:BoolToVisibilityConverter x:Key="BoolToVisConverter"/>
<converters:IndexConverter x:Key="IndexConverter"/>
<!-- Navisworks 2026 风格样式定义 -->
<Style x:Key="SectionHeaderStyle" TargetType="Label">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="#FF2B579A"/>
<Setter Property="Padding" Value="0,5,0,2"/>
</Style>
<Style x:Key="ActionButtonStyle" TargetType="Button">
<Setter Property="Background" Value="#FF4472C4"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderBrush" Value="#FF2B579A"/>
<Setter Property="Padding" Value="10,5"/>
<Setter Property="Margin" Value="0,0,10,0"/>
<Setter Property="FontWeight" Value="SemiBold"/>
</Style>
<Style x:Key="SecondaryButtonStyle" TargetType="Button">
<Setter Property="Background" Value="#FFE7F1FF"/>
<Setter Property="Foreground" Value="#FF2B579A"/>
<Setter Property="BorderBrush" Value="#FF4472C4"/>
<Setter Property="Padding" Value="8,4"/>
<Setter Property="Margin" Value="0,0,8,0"/>
</Style>
<Style x:Key="StatusTextStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="10"/>
<Setter Property="Foreground" Value="#FF666666"/>
<Setter Property="TextWrapping" Value="Wrap"/>
</Style>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/NavisworksTransportPlugin;component/src/UI/WPF/Resources/NavisworksStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
<!-- 转换器资源 -->
<converters:BoolToVisibilityConverter x:Key="BoolToVisConverter"/>
<converters:IndexConverter x:Key="IndexConverter"/>
</ResourceDictionary>
</UserControl.Resources>
<ScrollViewer VerticalScrollBarVisibility="Auto" Padding="10">
<StackPanel>
<!-- 区域1: 楼层属性设置(仅保留手动设置部分) -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,15" Padding="12">
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Label Content="楼层属性设置" Style="{StaticResource SectionHeaderStyle}"/>
@ -118,10 +93,10 @@ NavisworksTransport 分层管理页签视图 - 重构优化版本
</StackPanel>
</Border>
<!-- 区域2: 模型分层预览与保存 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,15" Padding="12">
<!-- 区域2: 分层预览与保存 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Label Content="模型分层预览与保存" Style="{StaticResource SectionHeaderStyle}"/>
<Label Content="分层预览与保存" Style="{StaticResource SectionHeaderStyle}"/>
<!-- 分层策略和深度选择 -->
<Grid Margin="0,5,0,10">
@ -152,7 +127,7 @@ NavisworksTransport 分层管理页签视图 - 重构优化版本
ItemsSource="{Binding DepthOptions}"
Margin="5,2" IsEnabled="{Binding IsNotProcessing}"/>
<Button Grid.Column="4"
Content="预览分层"
Content="预览"
Style="{StaticResource SecondaryButtonStyle}"
Command="{Binding PreviewSplitCommand}"
IsEnabled="{Binding CanPreviewSplit}"
@ -167,13 +142,13 @@ NavisworksTransport 分层管理页签视图 - 重构优化版本
</Grid>
<!-- 导出选项设置 -->
<Expander Header="导出选项设置" IsExpanded="False" Margin="0,5,0,5">
<Expander Header="NWD文件导出选项" IsExpanded="False" Margin="0,5,0,5">
<StackPanel Margin="10,10,0,5">
<TextBlock Text="配置NWD文件导出选项对应Navisworks导出对话框选项"
Style="{StaticResource StatusTextStyle}"
Margin="0,0,0,8"/>
<StackPanel>
<CheckBox Content="嵌入 ReCap 和纹理数据"
<CheckBox Content="嵌入ReCap和纹理数据"
IsChecked="{Binding EmbedXrefs}"
Margin="0,0,0,5"
ToolTip="将外部引用和纹理数据嵌入到导出的NWD文件中"/>
@ -186,20 +161,10 @@ NavisworksTransport 分层管理页签视图 - 重构优化版本
IsChecked="{Binding PreventObjectPropertyExport}"
Margin="0,0,0,5"
ToolTip="导出时不包含对象的属性信息,可减小文件大小"/>
<TextBlock Text="注:隐藏项目将自动排除(确保分层效果)"
Style="{StaticResource StatusTextStyle}"
Foreground="#FF666666"
FontStyle="Italic"
Margin="0,8,0,0"/>
</StackPanel>
</StackPanel>
</Expander>
<!-- 说明文字 -->
<TextBlock Text="点击[分层保存]时将弹出文件选择对话框,选择保存位置"
Style="{StaticResource StatusTextStyle}"
Margin="0,0,0,5"/>
<!-- 分层预览结果和操作按钮 -->
<GroupBox Header="分层预览结果" Margin="0,10,0,0" MinHeight="200">
<Grid>
@ -235,7 +200,7 @@ NavisworksTransport 分层管理页签视图 - 重构优化版本
<StackPanel Grid.Row="0"
VerticalAlignment="Center"
Visibility="{Binding ShowPreviewPrompt, Converter={StaticResource BoolToVisConverter}}">
<TextBlock Text="点击[预览分层]生成分层列表,或查看错误信息"
<TextBlock Text="点击[预览]生成分层列表,或查看错误信息"
Style="{StaticResource StatusTextStyle}"
HorizontalAlignment="Center"/>
</StackPanel>
@ -256,7 +221,7 @@ NavisworksTransport 分层管理页签视图 - 重构优化版本
</Border>
<!-- 区域3: 选择集保存 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,15" Padding="12">
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Label Content="选择集保存" Style="{StaticResource SectionHeaderStyle}"/>
@ -278,20 +243,6 @@ NavisworksTransport 分层管理页签视图 - 重构优化版本
FontWeight="SemiBold"
Foreground="#FF2B579A"
Margin="0,0,0,10"/>
<!-- 保存选项 -->
<StackPanel Grid.Row="2"
Orientation="Horizontal"
Margin="0,0,0,0">
<CheckBox Content="包含子节点"
IsChecked="{Binding IncludeChildNodes}"
Margin="0,0,15,0"/>
<CheckBox Content="保留材质贴图"
IsChecked="{Binding PreserveMaterials}"
Margin="0,0,15,0"/>
<CheckBox Content="生成预览图"
IsChecked="{Binding GeneratePreview}"/>
</StackPanel>
</Grid>
<!-- 保存按钮区域 -->
@ -317,7 +268,7 @@ NavisworksTransport 分层管理页签视图 - 重构优化版本
</Border>
<!-- 进度和状态区域 -->
<Border BorderBrush="#FFE0E0E0" BorderThickness="1" CornerRadius="4" Padding="12"
<Border BorderBrush="#FFE0E0E0" BorderThickness="1" CornerRadius="0" Padding="12"
Visibility="{Binding IsProcessing, Converter={StaticResource BoolToVisConverter}}">
<StackPanel>
<TextBlock Text="{Binding CurrentOperationText}"

View File

@ -20,69 +20,24 @@ NavisworksTransport 类别设置页签视图 - 参考分层管理页签的设计
d:DesignHeight="700" d:DesignWidth="480">
<UserControl.Resources>
<!-- 转换器资源 -->
<converters:BoolToVisibilityConverter x:Key="BoolToVisConverter"/>
<converters:IndexConverter x:Key="IndexConverter"/>
<!-- Navisworks 2026 风格样式定义 -->
<Style x:Key="SectionHeaderStyle" TargetType="Label">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="#FF2B579A"/>
<Setter Property="Padding" Value="0,5,0,2"/>
</Style>
<Style x:Key="ActionButtonStyle" TargetType="Button">
<Setter Property="Background" Value="#FF4472C4"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderBrush" Value="#FF2B579A"/>
<Setter Property="Padding" Value="10,5"/>
<Setter Property="Margin" Value="0,0,10,0"/>
<Setter Property="FontWeight" Value="SemiBold"/>
</Style>
<Style x:Key="SecondaryButtonStyle" TargetType="Button">
<Setter Property="Background" Value="#FFE7F1FF"/>
<Setter Property="Foreground" Value="#FF2B579A"/>
<Setter Property="BorderBrush" Value="#FF4472C4"/>
<Setter Property="Padding" Value="8,4"/>
<Setter Property="Margin" Value="0,0,8,0"/>
</Style>
<Style x:Key="StatusTextStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="10"/>
<Setter Property="Foreground" Value="#FF666666"/>
<Setter Property="TextWrapping" Value="Wrap"/>
</Style>
<Style x:Key="ParameterLabelStyle" TargetType="Label">
<Setter Property="Width" Value="80"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Padding" Value="0,0,5,0"/>
</Style>
<Style x:Key="ParameterInputStyle" TargetType="TextBox">
<Setter Property="Width" Value="80"/>
<Setter Property="Margin" Value="5,2"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
<Style x:Key="UnitLabelStyle" TargetType="Label">
<Setter Property="Width" Value="30"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Padding" Value="2,0,0,0"/>
<Setter Property="FontSize" Value="10"/>
<Setter Property="Foreground" Value="#FF666666"/>
</Style>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/NavisworksTransportPlugin;component/src/UI/WPF/Resources/NavisworksStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
<!-- 转换器资源 -->
<converters:BoolToVisibilityConverter x:Key="BoolToVisConverter"/>
<converters:IndexConverter x:Key="IndexConverter"/>
</ResourceDictionary>
</UserControl.Resources>
<ScrollViewer VerticalScrollBarVisibility="Auto" Padding="10">
<StackPanel>
<!-- 区域1: 模型选择和类别属性设置(整合区域) -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,15" Padding="12">
<!-- 区域1: 物流属性设置 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Label Content="模型选择与类别属性设置" Style="{StaticResource SectionHeaderStyle}"/>
<Label Content="物流属性设置" Style="{StaticResource SectionHeaderStyle}"/>
<!-- 模型选择状态显示 -->
<Grid Margin="0,5,0,15">
@ -96,23 +51,10 @@ NavisworksTransport 类别设置页签视图 - 参考分层管理页签的设计
FontWeight="SemiBold"
Foreground="#FF2B579A"
Margin="0,0,0,5"/>
<StackPanel Grid.Row="1"
Orientation="Horizontal"
Margin="0,0,0,0">
<Button Content="刷新选择"
Style="{StaticResource SecondaryButtonStyle}"
Command="{Binding RefreshSelectionCommand}"
ToolTip="检查当前在主界面中选择的模型"/>
<TextBlock Text="提示:请在主界面中选择需要设置属性的模型,然后点击刷新选择"
Style="{StaticResource StatusTextStyle}"
VerticalAlignment="Center"
Margin="10,0,0,0"/>
</StackPanel>
</Grid>
<!-- 类别属性设置 -->
<GroupBox Header="物流属性配置" Margin="0,5,0,0">
<GroupBox Header="物流属性" Margin="0,5,0,0">
<StackPanel Margin="10">
<!-- 第一行:物流类型和可通行性 -->
<Grid Margin="0,0,0,10">
@ -202,7 +144,7 @@ NavisworksTransport 类别设置页签视图 - 参考分层管理页签的设计
ToolTip="速度限制(米/秒)"/>
<Label Grid.Column="2" Content="米/秒" Style="{StaticResource UnitLabelStyle}" Width="40"/>
<TextBlock Grid.Column="3"
Text="默认推荐值:通道 0.8m/s电梯 0.5m/s楼梯 0.3m/s"
Text="推荐值:通道 0.8m/s电梯 0.5m/s楼梯 0.3m/s"
Style="{StaticResource StatusTextStyle}"
VerticalAlignment="Center"
Margin="10,0,0,0"/>
@ -227,10 +169,10 @@ NavisworksTransport 类别设置页签视图 - 参考分层管理页签的设计
</StackPanel>
</Border>
<!-- 区域2: 物流模型列表管理 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,15" Padding="12">
<!-- 区域2: 物流模型列表 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Label Content="物流模型列表管理" Style="{StaticResource SectionHeaderStyle}"/>
<Label Content="物流模型列表" Style="{StaticResource SectionHeaderStyle}"/>
<!-- 列表刷新控制 -->
<Grid Margin="0,5,0,10">
@ -286,7 +228,7 @@ NavisworksTransport 类别设置页签视图 - 参考分层管理页签的设计
</Border>
<!-- 区域3: 可见性控制 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,15" Padding="12">
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Label Content="显示模式控制" Style="{StaticResource SectionHeaderStyle}"/>
@ -313,7 +255,7 @@ NavisworksTransport 类别设置页签视图 - 参考分层管理页签的设计
</Border>
<!-- 状态显示区域 -->
<Border BorderBrush="#FFE0E0E0" BorderThickness="1" CornerRadius="4" Padding="12"
<Border BorderBrush="#FFE0E0E0" BorderThickness="1" CornerRadius="0" Padding="12"
Visibility="{Binding IsProcessing, Converter={StaticResource BoolToVisConverter}}">
<StackPanel>
<TextBlock Text="{Binding StatusText}"
@ -328,7 +270,7 @@ NavisworksTransport 类别设置页签视图 - 参考分层管理页签的设计
</Border>
<!-- 底部状态栏 -->
<Border BorderBrush="#FFE0E0E0" BorderThickness="1" CornerRadius="4" Padding="8"
<Border BorderBrush="#FFE0E0E0" BorderThickness="1" CornerRadius="0" Padding="8"
Background="#FFF8F9FA" Margin="0,5,0,0">
<TextBlock Text="{Binding StatusText}"
Style="{StaticResource StatusTextStyle}"

View File

@ -3,8 +3,8 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
功能说明:
1. 自动路径规划:起终点选择、车辆尺寸参数(长宽高)、安全间隙设置
2. 路径列表管理:新建、删除、重命名路径,显示路径状态
3. 手动路径编辑:开始编辑、结束编辑、清空路径、路径点管理
2. 路径列表:新建、删除、重命名路径,显示路径状态
3. 路径编辑:开始编辑、结束编辑、清空路径、路径点管理
4. 路径文件管理:导入、导出、另存为操作和状态显示
设计原则与Navisworks 2026风格一致480像素宽度现代化UI布局采用GroupBox分组
@ -19,74 +19,21 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
d:DesignHeight="800" d:DesignWidth="480">
<UserControl.Resources>
<!-- 转换器资源 -->
<converters:BoolToVisibilityConverter x:Key="BoolToVisConverter"/>
<!-- Navisworks 2026 风格样式定义 -->
<Style x:Key="SectionHeaderStyle" TargetType="Label">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="#FF2B579A"/>
<Setter Property="Padding" Value="0,5,0,2"/>
</Style>
<Style x:Key="ActionButtonStyle" TargetType="Button">
<Setter Property="Background" Value="#FF4472C4"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderBrush" Value="#FF2B579A"/>
<Setter Property="Padding" Value="10,5"/>
<Setter Property="Margin" Value="0,0,10,0"/>
<Setter Property="FontWeight" Value="SemiBold"/>
</Style>
<Style x:Key="SecondaryButtonStyle" TargetType="Button">
<Setter Property="Background" Value="#FFE7F1FF"/>
<Setter Property="Foreground" Value="#FF2B579A"/>
<Setter Property="BorderBrush" Value="#FF4472C4"/>
<Setter Property="Padding" Value="8,4"/>
<Setter Property="Margin" Value="0,0,8,0"/>
</Style>
<Style x:Key="StatusTextStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="10"/>
<Setter Property="Foreground" Value="#FF666666"/>
<Setter Property="TextWrapping" Value="Wrap"/>
</Style>
<Style x:Key="ParameterLabelStyle" TargetType="Label">
<Setter Property="Width" Value="80"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Padding" Value="0,0,5,0"/>
</Style>
<Style x:Key="ParameterInputStyle" TargetType="TextBox">
<Setter Property="Width" Value="80"/>
<Setter Property="Margin" Value="5,2"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
<Style x:Key="UnitLabelStyle" TargetType="Label">
<Setter Property="Width" Value="30"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Padding" Value="2,0,0,0"/>
<Setter Property="FontSize" Value="10"/>
<Setter Property="Foreground" Value="#FF666666"/>
</Style>
<Style x:Key="ReadOnlyTextBoxStyle" TargetType="TextBox">
<Setter Property="IsReadOnly" Value="True"/>
<Setter Property="Background" Value="#FFF5F5F5"/>
<Setter Property="BorderBrush" Value="#FFCCCCCC"/>
<Setter Property="Padding" Value="5,3"/>
<Setter Property="Margin" Value="5,2"/>
</Style>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/NavisworksTransportPlugin;component/src/UI/WPF/Resources/NavisworksStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
<!-- 转换器资源 -->
<converters:BoolToVisibilityConverter x:Key="BoolToVisConverter"/>
</ResourceDictionary>
</UserControl.Resources>
<ScrollViewer VerticalScrollBarVisibility="Auto" Padding="10">
<StackPanel>
<!-- 区域1: 自动路径规划 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,15" Padding="12">
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Label Content="自动路径规划" Style="{StaticResource SectionHeaderStyle}"/>
@ -185,16 +132,16 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
</Border>
<!-- 区域2: 路径列表管理 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,15" Padding="12">
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Label Content="路径列表管理" Style="{StaticResource SectionHeaderStyle}"/>
<Label Content="路径列表" Style="{StaticResource SectionHeaderStyle}"/>
<!-- 路径管理按钮 -->
<StackPanel Orientation="Horizontal" Margin="0,10,0,10">
<Button Content="新建路径"
<Button Content="手动创建"
Command="{Binding NewPathCommand}"
Style="{StaticResource ActionButtonStyle}"/>
<Button Content="删除路径"
<Button Content="删除"
Command="{Binding DeletePathCommand}"
Style="{StaticResource SecondaryButtonStyle}"
IsEnabled="{Binding SelectedPathRoute, Converter={x:Static converters:BoolToVisibilityConverter.IsNotNullToBoolConverter}}"/>
@ -229,22 +176,22 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
</StackPanel>
</Border>
<!-- 区域3: 手动路径编辑 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,15" Padding="12">
<!-- 区域3: 路径编辑 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Label Content="手动路径编辑" Style="{StaticResource SectionHeaderStyle}"/>
<Label Content="路径编辑" Style="{StaticResource SectionHeaderStyle}"/>
<!-- 编辑控制按钮 -->
<StackPanel Orientation="Horizontal" Margin="0,10,0,10">
<Button Content="开始编辑"
<Button Content="开始"
Command="{Binding StartEditCommand}"
Style="{StaticResource ActionButtonStyle}"
IsEnabled="{Binding CanExecuteStartEdit}"/>
<Button Content="结束编辑"
<Button Content="结束"
Command="{Binding EndEditCommand}"
Style="{StaticResource SecondaryButtonStyle}"
IsEnabled="{Binding CanExecuteEndEdit}"/>
<Button Content="清空路径"
<Button Content="清空"
Command="{Binding ClearPathCommand}"
Style="{StaticResource SecondaryButtonStyle}"
Background="#FFFFE6E6"
@ -308,16 +255,16 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
</Border>
<!-- 区域4: 路径文件管理 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,15" Padding="12">
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Label Content="路径文件管理" Style="{StaticResource SectionHeaderStyle}"/>
<!-- 文件操作按钮 -->
<StackPanel Orientation="Horizontal" Margin="0,10,0,10">
<Button Content="导入路径"
<Button Content="导入"
Command="{Binding ImportPathCommand}"
Style="{StaticResource SecondaryButtonStyle}"/>
<Button Content="导出路径"
<Button Content="导出"
Command="{Binding ExportPathCommand}"
Style="{StaticResource SecondaryButtonStyle}"
IsEnabled="{Binding CanExecuteExportPath}"/>
@ -346,7 +293,7 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
</Border>
<!-- 区域5: 3D交互指南 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,0" Padding="12">
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,0" Padding="12">
<StackPanel>
<Label Content="3D交互操作指南" Style="{StaticResource SectionHeaderStyle}"/>
@ -362,10 +309,10 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
Style="{StaticResource StatusTextStyle}"
Margin="10,2"/>
<TextBlock Text="手动路径编辑:"
<TextBlock Text="路径编辑:"
FontWeight="SemiBold"
Margin="0,8,0,2"/>
<TextBlock Text="• 选择路径后点击&quot;开始编辑&quot;进入编辑模式"
<TextBlock Text="• 选择路径后点击&quot;编辑&quot;进入编辑模式"
Style="{StaticResource StatusTextStyle}"
Margin="10,2"/>
<TextBlock Text="• 在3D视图中点击可通行的物流模型添加路径点"
@ -374,7 +321,7 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
<TextBlock Text="• 使用列表中的&quot;删除&quot;按钮移除不需要的路径点"
Style="{StaticResource StatusTextStyle}"
Margin="10,2"/>
<TextBlock Text="• 编辑完成后点击&quot;结束编辑&quot;保存修改"
<TextBlock Text="• 编辑完成后点击&quot;结束&quot;保存修改"
Style="{StaticResource StatusTextStyle}"
Margin="10,2"/>
</StackPanel>

View File

@ -18,61 +18,32 @@ NavisworksTransport 系统管理页签视图 - 采用与其他页签一致的Nav
d:DesignHeight="800" d:DesignWidth="480">
<UserControl.Resources>
<!-- Navisworks 2026 风格样式定义 -->
<Style x:Key="SectionHeaderStyle" TargetType="Label">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="#FF2B579A"/>
<Setter Property="Padding" Value="0,5,0,2"/>
</Style>
<Style x:Key="ActionButtonStyle" TargetType="Button">
<Setter Property="Background" Value="#FF4472C4"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderBrush" Value="#FF2B579A"/>
<Setter Property="Padding" Value="10,5"/>
<Setter Property="Margin" Value="0,0,10,0"/>
<Setter Property="FontWeight" Value="SemiBold"/>
</Style>
<Style x:Key="SecondaryButtonStyle" TargetType="Button">
<Setter Property="Background" Value="#FFE7F1FF"/>
<Setter Property="Foreground" Value="#FF2B579A"/>
<Setter Property="BorderBrush" Value="#FF4472C4"/>
<Setter Property="Padding" Value="8,4"/>
<Setter Property="Margin" Value="0,0,8,0"/>
</Style>
<Style x:Key="StatusTextStyle" TargetType="Label">
<Setter Property="FontSize" Value="10"/>
<Setter Property="Foreground" Value="#FF666666"/>
</Style>
<!-- 引用共享的Navisworks 2026样式资源 -->
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/NavisworksTransportPlugin;component/src/UI/WPF/Resources/NavisworksStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
<!-- 系统管理页面特有的样式 -->
<Style x:Key="InfoTextStyle" TargetType="Label">
<Setter Property="FontSize" Value="10"/>
<Setter Property="Foreground" Value="{StaticResource NavisworksTextBrush}"/>
<Setter Property="Padding" Value="0,2"/>
</Style>
<Style x:Key="InfoTextStyle" TargetType="Label">
<Setter Property="FontSize" Value="10"/>
<Setter Property="Foreground" Value="#FF666666"/>
<Setter Property="Padding" Value="0,2"/>
</Style>
<Style x:Key="ParameterLabelStyle" TargetType="Label">
<Setter Property="Width" Value="80"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Padding" Value="0,0,5,0"/>
<Setter Property="FontSize" Value="10"/>
</Style>
<Style x:Key="StatusLabelStyle" TargetType="Label">
<Setter Property="FontSize" Value="10"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Foreground" Value="#FF2B579A"/>
<Setter Property="Padding" Value="0,2"/>
</Style>
<Style x:Key="StatusLabelStyle" TargetType="Label">
<Setter Property="FontSize" Value="10"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="Foreground" Value="{StaticResource NavisworksPrimaryBrush}"/>
<Setter Property="Padding" Value="0,2"/>
</Style>
</ResourceDictionary>
</UserControl.Resources>
<ScrollViewer VerticalScrollBarVisibility="Auto" Padding="10">
<StackPanel>
<!-- 区域1: 日志管理 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,15" Padding="12">
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Label Content="日志管理" Style="{StaticResource SectionHeaderStyle}"/>
@ -97,7 +68,7 @@ NavisworksTransport 系统管理页签视图 - 采用与其他页签一致的Nav
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="日志级别:" Style="{StaticResource ParameterLabelStyle}" Width="60"/>
<Label Grid.Column="0" Content="日志级别:" Style="{StaticResource ParameterLabelStyle}" Width="80"/>
<ComboBox Grid.Column="1"
ItemsSource="{Binding LogLevels}"
SelectedItem="{Binding SelectedLogLevel}"
@ -113,7 +84,7 @@ NavisworksTransport 系统管理页签视图 - 采用与其他页签一致的Nav
</Border>
<!-- 区域2: 插件设置 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,15" Padding="12">
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Label Content="插件设置" Style="{StaticResource SectionHeaderStyle}"/>
@ -148,7 +119,7 @@ NavisworksTransport 系统管理页签视图 - 采用与其他页签一致的Nav
</Border>
<!-- 区域3: 系统信息 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,15" Padding="12">
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Label Content="系统信息" Style="{StaticResource SectionHeaderStyle}"/>
@ -194,7 +165,7 @@ NavisworksTransport 系统管理页签视图 - 采用与其他页签一致的Nav
</Border>
<!-- 区域4: 性能监控 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,0" Padding="12">
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,0" Padding="12">
<StackPanel>
<Label Content="性能监控" Style="{StaticResource SectionHeaderStyle}"/>