Skip to content

VM-Bound Docking Window State Mixin#1039

Merged
wieslawsoltes merged 3 commits intomasterfrom
feature/docking-window-state-mixin-sync
Feb 11, 2026
Merged

VM-Bound Docking Window State Mixin#1039
wieslawsoltes merged 3 commits intomasterfrom
feature/docking-window-state-mixin-sync

Conversation

@wieslawsoltes
Copy link
Owner

PR Summary: VM-Bound Docking Window State Mixin

Branch

  • feature/docking-window-state-mixin-sync

Goal

Implement optional VM-bound window state synchronization so dockables can bind and drive:

  • open/closed lifecycle
  • active/focused state
  • selected/tab state
  • docking window state transitions

while keeping layout and view-model state synchronized both directions with loop protection.

Commits

  1. 804c8797a Add docking window state mixin and factory synchronization
  2. 74744c977 Expand unit and headless coverage for window state sync
  3. 39316f137 Document docking window state mixin behavior

What Was Implemented

1) New core contracts

Added:

  • src/Dock.Model/Core/IDockingWindowState.cs
  • src/Dock.Model/Core/IDockingWindowStateSync.cs
  • src/Dock.Model/Core/DockingWindowStateProperty.cs

IDockingWindowState exposes:

  • IsOpen
  • IsActive
  • IsSelected
  • DockingState

IDockingWindowStateSync exposes the callback used by model objects to request layout updates from property changes.

2) Factory synchronization engine

Added:

  • src/Dock.Model/FactoryBase.DockingWindowStateSync.cs

Implemented two-way synchronization with:

  • coalescing (HashSet<IDockable>) for reentrancy protection
  • scoped suppression depth guard for layout->VM and VM->layout feedback loops
  • request handlers:
    • IsOpen -> hide/restore
    • IsSelected -> owner ActiveDockable
    • IsActive -> root focus synchronization
    • DockingState -> docking transitions (DockAsDocument, pin/unpin, float, hide/restore)
  • state projection helpers:
    • resolved DockingState
    • IsOpen
    • IsSelected
    • IsActive

3) Lifecycle integration

Updated:

  • src/Dock.Model/FactoryBase.Init.cs
  • src/Dock.Model/FactoryBase.Events.cs
  • src/Dock.Model/FactoryBase.DockingState.cs

Key integration points:

  • dockable.Factory = this now applies to all dockables during init
  • synchronization triggered from add/remove/hide/restore/focus/active flows
  • state projection after docking operations

4) Dockable model support across all model variants

Updated DockableBase + Document + Tool implementations in:

  • Mvvm
  • ReactiveUI
  • Avalonia
  • Inpc
  • Prism
  • ReactiveProperty
  • CaliburMicro

Changes include:

  • DockingState setter callback into IDockingWindowStateSync
  • runtime-only properties on document/tool models:
    • IsOpen
    • IsActive
    • IsSelected
  • serialization-exclusion for runtime state ([IgnoreDataMember], [JsonIgnore] where applicable)

5) Additional correctness fix

Adjusted visibility/selection/active projection for hidden ancestor scenarios:

  • if a dockable is hidden via hidden parent chain, IsOpen, IsSelected, and IsActive are forced false

This prevents stale "open/selected/active" flags for descendants of hidden containers.

Tests Added / Updated

Updated:

  • tests/Dock.Model.Mvvm.UnitTests/FactoryTests.cs
  • tests/Dock.Model.ReactiveUI.UnitTests/FactoryTests.cs
  • tests/Dock.Model.Avalonia.UnitTests/FactoryTests.cs
  • tests/Dock.Avalonia.HeadlessTests/FactoryTests.cs
  • tests/Dock.Model.Avalonia.UnitTests/AvaloniaDockSerializerTests.cs

Coverage includes:

  • layout -> VM synchronization
  • VM -> layout synchronization
  • hidden-state behavior
  • hidden ancestor behavior for child flags
  • serializer exclusion of runtime mixin properties

Documentation Updates

Updated:

  • docfx/articles/dock-dockable-properties.md
  • docfx/articles/dock-state.md

Docs now describe:

  • purpose and semantics of IDockingWindowState
  • runtime-only properties vs persisted state
  • synchronization behavior and expectations

Validation

Executed full solution validation:

  • dotnet test Dock.slnx -c Release --no-restore

Result: all tests passed.

Compatibility / Migration Notes

  • Feature is additive and optional.
  • Existing dockables that do not implement IDockingWindowState are unaffected.
  • Runtime flags (IsOpen, IsActive, IsSelected) are intentionally non-serialized.

Risk Notes

  • Main risk area was reentrancy/feedback loops; mitigated via suppression scope + per-dockable coalescing.
  • Hidden ancestor state projection had an edge case and is explicitly covered with new regression tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant