PR-M3: Persist viewer panel layout in ViewerSettings#129
Merged
Conversation
- Add IsLeftDockOpen/IsRightDockOpen/IsBottomDockOpen, LastSelectedRightTab, LastSelectedBottomTab, and PanelSizes to ViewerSettings. - Restore dock visibility, selected tabs, and panel sizes on startup; user-driven tab selection writes back to settings. - Add CollapsibleColumn.SavedWidth / CollapsibleRow.SavedHeight attached properties that two-way bind dock widths/height to the view model. - Add SplitterPersistence.SavedFraction attached property for inner GridSplitter star ratios (Datasets / Catalog tabs). - Add DebouncedSettingsSaver (500 ms, System.Threading.Timer) to coalesce rapid splitter drags into a single disk write; MainWindow.Closed flushes pending writes on shutdown. - Restore-immediately precedence: persisted IsRightDockOpen=true opens the dock at startup without waiting for content signals. - Settings tab exemption preserved (Left dock only). - 22 new tests (12 layout persistence + 6 debouncer + earlier baseline). Viewer test count 346 → 368. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
Performance Gate✅ PASSED — no regressions. Threshold: 10.0%, MAD multiplier (k): 3.0, retry-zone mult: 2.0× Scenario summary
exchange-set-openIteration statistics
Spans (sum of all iterations)
Metrics
s101-portray-coldIteration statistics
Spans (sum of all iterations)
Metrics
s101-portray-warmIteration statistics
Spans (sum of all iterations)
Metrics
s101-render-warmIteration statistics
Spans (sum of all iterations)
Metrics
s102-coverageIteration statistics
Spans (sum of all iterations)
Metrics
s102-coverage-openIteration statistics
Spans (sum of all iterations)
Metrics
s102-coverage-render-largeIteration statistics
Spans (sum of all iterations)
Metrics
s124-vectorIteration statistics
Spans (sum of all iterations)
Metrics
s201-vectorIteration statistics
Spans (sum of all iterations)
Metrics
Generated by EncDotNet.S100.PerfReport gate command |
The OnSavedWidthChanged / OnSavedHeightChanged class handlers only fire when the property's value actually changes. On first run the bound view-model value is null, which matches the attached property's default of null — so no Changed event fired and the WidthProperty / HeightProperty observer was never installed. Result: splitter drags never reached SavedWidth / SavedHeight and nothing was persisted. Fix: register a global ColumnDefinition.WidthProperty.Changed / RowDefinition.HeightProperty.Changed class handler in the static ctor. Gate inside on column.IsSet(SavedWidthProperty) / row.IsSet(SavedHeightProperty) — IsSet returns true once a binding has been assigned, even when the bound value equals the default. Verified manually: resize the left dock, restart, restored width is correct. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sets Mapsui Map.BackColor to RGB(170, 211, 223) so the map area visually blends with the chart's water when zoomed beyond the OSM tile layer's extent. Previously the empty area outside basemap coverage rendered as white, making it hard to distinguish the map control from side panels at low zoom. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…out-persistence # Conflicts: # src/EncDotNet.S100.Viewer/MainWindow.axaml.cs
The 'fire after delay' and 'coalesce' tests asserted on a save counter after a fixed Thread.Sleep window. On slower CI runners (Linux build, windows-11-arm) the 50 ms / 100 ms debounce timer plus dispatch overhead occasionally exceeded the 200 ms / 300 ms post-sleep window, producing intermittent failures. Replace the post-sleep assertion with a ManualResetEventSlim that the save action sets, then Wait(5s) for it. The coalesce test still keeps a final Thread.Sleep after the first fire to let any incorrectly-scheduled extra fires land before we assert coalescence (the bug it's guarding against would *cause* extra fires, not fewer, so we still need a passive window for it). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Persists viewer panel layout across restarts: per-dock visibility (left/right/bottom), selected tab per dock (right + bottom; left dock keeps existing
LastSelectedActivitysemantics with Settings-tab exemption), and panel sizes (three outer docks + Datasets/Catalog inner splitters).Highlights
IsLeftDockOpen(defaulttrue),IsRightDockOpen/IsBottomDockOpen(defaultfalse),LastSelectedRightTab,LastSelectedBottomTab,Panels(newPanelSizesclass with nullable size fields).LastSelectedActivitykept for back-compat (XML doc clarifies it is the left dock).WireAutoOpenSubscriptions; stale persisted ids fall back to the first registered tab of that dock. Stores_settingsInitializedflag so setters only persist after hydration. AddsOnShutdown()that flushes the size-saver.SavedWidth/SavedHeightattached properties (two-way). LazyPropertyChangedsubscription pushes user-driven changes back to the view model.SavedFraction(0–1) on innerGridSplitters; rewrites the two adjacent star definitions preserving their total star factor.System.Threading.Timer,RequestSave/Flush/Dispose. UI dispatch optional (omitted in tests). Save action wrapped in try/catch so I/O failures don't crash the viewer.MainWindow.ClosedcallsOnShutdown→Flushso the last drag is never lost.IsRightDockOpen=trueopens the dock at startup without waiting for the next content signal; PR-M4 auto-open events still fire but are no-ops when the dock is already open.Tests
Viewer test count: 346 → 368 (+22).
DebouncedSettingsSaverTests(6): single fire, coalesce, Flush, no-op Flush, Dispose flushes, swallows exceptions.LayoutPersistenceTests(16): default visibility (3), restore from settings (3), toggle writes back, tab restore + stale-id fallback (3), user selection writes back, restore-immediately precedence vs. auto-open, panel-size hydration, inner-split persistence (2),OnShutdowndoesn't throw.Decisions / notes
LastSelectedActivityname (no rename) — avoids back-compat read+write code; new XML doc clarifies it's the left dock.System.Threading.Timer(testable, no UI-thread coupling). UI dispatcher (Dispatcher.UIThread.Post) is passed in byMainViewModel.doublefraction [0, 1] of the previous row/column relative to the sum of two adjacent star factors; preserves the original star total when rewriting.CollapsibleColumn/CollapsibleRowalready maintainedRememberedWidth/RememberedHeightfor collapse/restore. The newSavedWidth/SavedHeightare independent two-way bindings; they observe Width/Height changes viaPropertyChangedand only write back when the value is absolute and meaningfully changed (> 0.5 px).SplitterPersistence.FindRows/FindColumnsare benign (loop body always breaks); left as-is to keep the loop shape readable.Out of scope (defer markers in code)
TODO PR-M-future: persist dataset-panel inner tab selection (validation vs. properties).TODO PR-M-future: persist activity-bar collapsed state.Acceptance
dotnet build EncDotNet.S100.slnx -c Release— clean (2 pre-existing warnings, none new in changed projects).dotnet test tests/EncDotNet.S100.Viewer.Tests/ -c Release— 368 passed, 0 failed.Closes the PR-M3 TODOs left at
MainViewModel.cs(PR-M4 markers on the threeIsXDockOpensetters).