- Single selection: SaveFileDialog with path name as default filename
- Multi selection: FolderBrowserDialog to pick output directory
- Export format: XML for multi (simpler UX), selectable for single
- DataGrid: SelectionMode Extended with RowStyle IsSelected binding
- PathRouteViewModel: add IsSelected property
- Export: iterates selected paths, saves each to separate file
- Ctrl/Shift+click to multi-select, then Export button batches them
- Also regenerate all PathPoint.Id to avoid UNIQUE constraint on PathPoints.Id
- Call RecalculateRoute() to rebuild edges with new point references
- Edge constructor auto-generates new Id, so edges are fresh too
- ParseRouteElement used route.AddPoint() which called RecalculateAndSaveRoute
- This saved the path to DB with original name before ImportPathCommand could rename it
- Changed to route.Points.Add() + route.RecalculateRoute() to skip DB save
- Only ImportPathCommand → AddRoute → SavePathToDatabase now persists renamed path
- Rename '导出选中路径' to '导出', move before '导出全部'
- Import dialog: enable MultiSelect, loop through all selected files
- Aggregate import results across files
EditableNumberConverter.ConvertBack was throwing FormatException
when users typed '=' or other non-numeric characters, causing
WPF binding validation to crash the application on focus change.
Changed to return Binding.DoNothing to silently reject invalid input.
- New FaceInferToolPlugin: pixel-neighborhood method with {2,5,10}px offsets
- New FaceInferResult data class
- Test button in SystemManagement page
- Cursor: MarkupAutoPoly (arrow + dashed box)
- Uses project-standard tools: FindNamedParentContainer, viewpoint.Position
- Design doc at doc/design/2026/face-infer-tool-design.md
Ground and Hoisting paths don't consume fragment reference rotation, only Rail does.
Replace manual PathType checks with the existing semantic utility method.
Also fix GetPathRouteSync SELECT missing IsTwoPointVertical column.
- Skip height constraints, orthogonalization, and intermediate point insertion
- Auto-recalculate LiftHeight from elevation difference between the two points
- Add '2点路径' button in AerialHeightDialog for pure vertical lift
- Handle IsTwoPointMode on first click to create 2-point path directly
- Fix PathTargetFrameResolver to accept 2-point Hoisting paths
- Fix animation yaw for 2-point vertical paths (use _currentYaw)
- Fix TryApplyPlanarRealObjectStartIncrementalTransform to translate even
when no rotation change (was skipping translation for pure vertical)
- Guard _pathPoints[2] access in animation code for <3 points
- OnTreeViewItemLeftClick: use e.OriginalSource.DataContext directly,
not visual tree traversal (FindAncestor)
- _isProgrammaticExpand prevents Expanded event from triggering bulk
LazyLoadChildren during ExpandAndSelect
- OnNavisSelectionChanged: synchronous processing with _isInternalSelection
guard prevents feedback loop
- Try-catch wrappers on all COM API call sites (FromModelItem, BuildNode)
- MaxFullDisplayDepth=2: only show full tree up to level 2
- Beyond max depth, nodes only expand if they have an alias
- AliasNodeViewModel.Depth tracks tree depth
- Reduces loaded nodes for large models with deep unaliased branches
- TryConnectToDatabase: createIfMissing=false (only connect, don't create)
- New BeforeSaveAlias event + EnsureDatabaseCreated: creates DB on first save
- Matches MainPlugin.TryConnectPathDatabase pattern
- TryConnectToDatabase calls DatabaseInitialize(createIfMissing:true)
- Alias saving now creates .db file if it doesn't exist
- Removed delayed retry code (no longer needed)
- Added diagnostic logging for SetDataStore/RefreshAliases
- Two stacked TextBlocks: alias (red, bold) + [原文] (black, bold)
- [原文] suffix only visible when HasAlias=true
- CommitEdit/toolbar: treat unchanged text as no alias (set to null)
- Fixes: nodes edited without actual changes no longer show false [原文] suffix