Skip to content

Fix global target and proportions#1030

Merged
wieslawsoltes merged 6 commits intomasterfrom
issue-1022-global-target-and-proportions
Feb 9, 2026
Merged

Fix global target and proportions#1030
wieslawsoltes merged 6 commits intomasterfrom
issue-1022-global-target-and-proportions

Conversation

@wieslawsoltes
Copy link
Copy Markdown
Owner

@wieslawsoltes wieslawsoltes commented Feb 8, 2026

Investigation Report and PR Summary: Fix for Issue #1022

Linked Issue

Issue

Docking to Top after resizing a Bottom-docked area could produce incorrect split behavior:

  • split applied to an unexpected subtree,
  • thin strip / imbalanced panes,
  • non-0.5/0.5 behavior when splitting single tool/document docks.

Reproduction

Using DockMvvmSample from the issue:

  1. Dock a document/tool to Bottom.
  2. Resize that split area.
  3. Dock another document/tool to Top (or split a single dock).

Detailed Investigation

Phase 1: Operation-precedence ambiguity

When both local and global targets were available, execution could pick global too eagerly.

Implemented:

  • explicit global-vs-local operation preference logic,
  • consistent use in Over(...), Drop(...), and drag preview operation selection.

Phase 2: Wrong global target resolution (core issue)

Global validation/execution resolved target from focused active pane (Layout.ActiveDockable) in paths where the hovered drop context should have been authoritative.

Implemented:

  • drop-context-first global target resolution,
  • fallback to active dock only when drop context cannot resolve a dock.

Applied in:

  • DockControlState,
  • HostWindowState,
  • ManagedHostWindowState,
  • global adorner decisions in DockManagerState.

Phase 3: Split proportion state drift (Proportion vs CollapsedProportion)

Remaining bad ratios came from stale CollapsedProportion values overriding fresh split values in proportional layout restore paths.

Implemented in FactoryBase:

  • synchronized split-critical assignments so Proportion and CollapsedProportion are updated together,
  • effective-share split behavior when target proportion is NaN,
  • stale reused-dock proportion reset in fallback split layout creation.

Phase 4: Global docking proportion behavior consistency

DockSettings.GlobalDockingProportion needed to apply reliably after global drops while preserving safety guards.

Final behavior:

  • apply global proportion only when source root and target root are available,
  • keep sourceDockable.Owner != null guard,
  • update both Owner.Proportion and Owner.CollapsedProportion.

Phase 5: Service quality refactor and consolidation

Refactor was first split into multiple services, then consolidated to reduce indirection and improve maintainability.

Final architecture:

  • one service: IGlobalDockingService / GlobalDockingService.
  • responsibilities:
    • resolve global target dock,
    • choose global-vs-local operation,
    • apply global docking proportion.

Important parity note:

  • strict pre-refactor behavior was preserved by passing precomputed roots from DockControlState into the service for proportion application (no broadened fallback semantics).

Commit Timeline

  • 5315650ce Fix global drop target resolution and operation precedence
  • 1fe128d7f Fix split proportion propagation after resize and fallback splits
  • debe90f6e Set GlobalDockingProportion default to 0.5
  • f204ffa81 Refactor global docking decisions into dedicated services
  • 00d174973 Restore pre-refactor global proportion gating semantics
  • bd0dfa043 Consolidate global docking rules into single service

Final Fix Summary

  1. Global target resolution now follows hovered drop context deterministically.
  2. Global/local operation choice is explicit and consistently applied.
  3. Split logic handles NaN proportions using effective target share in optimized split paths.
  4. Fallback split layout no longer reuses stale split proportions from prior owners.
  5. Split-critical updates synchronize Proportion and CollapsedProportion.
  6. Global proportion application preserves strict pre-refactor gating semantics.
  7. Global docking logic is consolidated into a single internal service.
  8. Default DockSettings.GlobalDockingProportion is 0.5.

Test Coverage Added/Updated

tests/Dock.Avalonia.HeadlessTests/DockControlStateTests.cs

  • operation precedence scenarios,
  • global target resolution from drop context,
  • global proportion apply guard scenarios,
  • service-level coverage now runs through consolidated GlobalDockingService.

tests/Dock.Avalonia.HeadlessTests/WindowStateGlobalTargetResolutionTests.cs

  • HostWindowState_ValidateGlobal_UsesDropContextTarget_WithoutDockControlAncestor
  • ManagedHostWindowState_ValidateGlobal_UsesDropContextTarget_WithoutDockControlAncestor

tests/Dock.Avalonia.HeadlessTests/FactorySplitTests.cs

  • updated effective-share split behavior for NaN proportions,
  • fallback split stale proportion reset coverage,
  • collapsed proportion synchronization coverage.

tests/Dock.Avalonia.HeadlessTests/OptimizedSplitLayoutTests.cs

  • OptimizedSplitLayout_WithNaNTarget_UsesEffectiveShareForHalfSplit

tests/Dock.Model.UnitTests/DockServiceSplitProportionTests.cs

  • regression scenario for top-after-bottom-resize split behavior.

Validation

Executed:

  • dotnet test tests/Dock.Avalonia.HeadlessTests/Dock.Avalonia.HeadlessTests.csproj --configuration Release --filter "FullyQualifiedName~DockControlStateTests|FullyQualifiedName~WindowStateGlobalTargetResolutionTests"
    • Passed: 14, Failed: 0
  • dotnet test tests/Dock.Avalonia.HeadlessTests/Dock.Avalonia.HeadlessTests.csproj --configuration Release
    • Passed: 461, Failed: 0
  • dotnet test tests/Dock.Model.UnitTests/Dock.Model.UnitTests.csproj --configuration Release
    • Passed: 78, Failed: 0

Files Changed (Final)

  • src/Dock.Avalonia/Internal/DockManagerState.cs
  • src/Dock.Avalonia/Internal/DockControlState.cs
  • src/Dock.Avalonia/Internal/HostWindowState.cs
  • src/Dock.Avalonia/Internal/ManagedHostWindowState.cs
  • src/Dock.Avalonia/Internal/Services/IGlobalDockingService.cs
  • src/Dock.Avalonia/Internal/Services/GlobalDockingService.cs
  • src/Dock.Model/FactoryBase.cs
  • src/Dock.Settings/DockSettings.cs
  • docfx/articles/dock-settings.md
  • tests/Dock.Avalonia.HeadlessTests/DockControlStateTests.cs
  • tests/Dock.Avalonia.HeadlessTests/WindowStateGlobalTargetResolutionTests.cs
  • tests/Dock.Avalonia.HeadlessTests/FactorySplitTests.cs
  • tests/Dock.Avalonia.HeadlessTests/OptimizedSplitLayoutTests.cs
  • tests/Dock.Model.UnitTests/DockServiceSplitProportionTests.cs

PR Summary (Ready to Use)

This PR fixes issue #1022 by correcting global drop target resolution and split proportion state handling across docking paths, then hardening maintainability with a single consolidated global docking service. The fix ensures global docking resolves from the hovered drop context rather than unrelated focused panes, preventing wrong-subtree splits (including right-panel mis-targeting). Split behavior now consistently handles unset (NaN) proportions via effective-share logic, avoids stale reused-dock proportion leakage in fallback layouts, and keeps Proportion and CollapsedProportion synchronized so collapsed state restore does not override fresh split ratios. Global proportion assignment remains strictly gated to the original semantics (pre-refactor parity preserved) while applying both proportion fields when valid. Default GlobalDockingProportion is set to 0.5. Expanded regression coverage spans dock-control, host-window, model split behavior, and the top-after-bottom-resize scenario. All relevant full suites pass.

Fixes #1022

@wieslawsoltes wieslawsoltes merged commit 5e7ac9a into master Feb 9, 2026
9 checks passed
@wieslawsoltes wieslawsoltes deleted the issue-1022-global-target-and-proportions branch February 9, 2026 08:14
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.

Docking to Top after resizing a bottom-docked document produces incorrect split proportions (pane becomes non-proportional / thin strip)

1 participant