Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions docfx/articles/dock-capability-policies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Capability Policies and Overrides

Dock supports layered capability resolution for all core interaction flags:

- `CanClose`
- `CanPin`
- `CanFloat`
- `CanDrag`
- `CanDrop`
- `CanDockAsDocument`

This enables global policy defaults, per-dock policy tuning, and per-window exceptions.

## Policy layers and precedence

Effective capability values are resolved in this order:

1. Base dockable flag (`IDockable.Can*`)
2. Root policy (`IRootDock.RootDockCapabilityPolicy`)
3. Dock policy (`IDock.DockCapabilityPolicy`)
4. Dockable override (`IDockable.DockCapabilityOverrides`)

Later layers override earlier layers when a value is set (`bool?` value is not `null`).

`null` means "inherit".

## API surface

- `DockCapabilityPolicy` (`Dock.Model.Core`)
- `DockCapabilityOverrides` (`Dock.Model.Core`)
- `IRootDock.RootDockCapabilityPolicy`
- `IDock.DockCapabilityPolicy`
- `IDockable.DockCapabilityOverrides`
- `DockCapabilityResolver` for explicit evaluation
- `IDockManager.LastCapabilityEvaluation` for diagnostics when validation is blocked by capability policy

## Example

```csharp
var root = factory.CreateRootDock();
root.RootDockCapabilityPolicy = new DockCapabilityPolicy
{
CanFloat = false
};

var tools = factory.CreateToolDock();
tools.DockCapabilityPolicy = new DockCapabilityPolicy
{
CanFloat = true
};

var explorer = factory.CreateTool();
explorer.DockCapabilityOverrides = new DockCapabilityOverrides
{
CanFloat = false
};
```

In this example, floating is:

- globally disabled at root,
- re-enabled for the tool dock,
- disabled again for one specific tool.

## Validation and diagnostics

Dock validation (`IDockManager`) and core factory operations now use effective capability values.

When an operation is rejected by capability policy, `IDockManager.LastCapabilityEvaluation` provides:

- evaluated capability,
- source layer (`Dockable`, `RootPolicy`, `DockPolicy`, `DockableOverride`),
- effective value and a diagnostic message.

## UI behavior

Default Fluent menus and drag entry points use effective capability resolution, so blocked actions are hidden/disabled consistently with runtime validation.

## Sample

`DockXamlReactiveUISample` includes:

- root, tool-dock, and document-dock capability policy controls,
- first generated item capability override controls,
- live testing against items-source generated windows.
3 changes: 3 additions & 0 deletions docfx/articles/dock-dockable-properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Dockable items such as documents, tools and docks implement the `IDockable` inte
| `CanDrag` | Enables dragging the dockable to another position. |
| `CanDrop` | Determines if other dockables can be dropped onto this one. |
| `CanDockAsDocument` | Controls whether the dockable can be docked as a tabbed document. |
| `DockCapabilityOverrides` | Optional per-dockable capability overrides (`bool?` values). Highest-precedence layer in capability resolution. |
| `IsModified` | Marks a dockable as having unsaved changes. |
| `DockGroup` | Group identifier that restricts which dockables can dock together. See [Docking Groups](dock-docking-groups.md). |
| `AllowedDockOperations` | Allowed docking operations when the dockable is dragged (`DockOperationMask`). |
Expand Down Expand Up @@ -68,6 +69,8 @@ In XAML you set them as attributes:

`DockingState` is maintained by factory operations (`PinDockable`, `UnpinDockable`, `FloatDockable`, `HideDockable`, `RestoreDockable`) and can be used by UI bindings for diagnostics or state-aware visuals.

Capability values can also be governed by policy layers at root and dock level. See [Capability policies and overrides](dock-capability-policies.md).

## Window State Mixin

`Document` and `Tool` models implement `IDockingWindowState`, which adds bindable runtime properties:
Expand Down
37 changes: 37 additions & 0 deletions docfx/articles/dock-docking-constraints.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,40 @@ tool.AllowedDockOperations = DockOperationMask.Left | DockOperationMask.Fill | D

These constraints affect validation and the docking indicators, so disallowed operations are hidden and rejected.

## Capability policies and per-window overrides

For larger layouts, use capability policies to set defaults at root and dock scope, then apply focused overrides per window:

- `IRootDock.RootDockCapabilityPolicy`
- `IDock.DockCapabilityPolicy`
- `IDockable.DockCapabilityOverrides`

Policy precedence is:

1. dockable `Can*` flags
2. root policy
3. dock policy
4. dockable override

`null` in policy/override means inherit.

```csharp
root.RootDockCapabilityPolicy = new DockCapabilityPolicy
{
CanFloat = false
};

toolDock.DockCapabilityPolicy = new DockCapabilityPolicy
{
CanFloat = true
};

tool.DockCapabilityOverrides = new DockCapabilityOverrides
{
CanFloat = false
};
```

Use `IDockManager.LastCapabilityEvaluation` to inspect why validation was blocked by policy.

See [Capability policies and overrides](dock-capability-policies.md) for full details.
1 change: 1 addition & 0 deletions docfx/articles/dock-itemssource.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ A custom `ItemContainerGenerator` can fully override this behavior.
- By default, `ToolDock` creates a `Tool` for each item and stores the item in `Tool.Context`.
- The tab title is derived from `Title`, `Name`, or `DisplayName` properties on the item (in that order), falling back to `ToString()`.
- `CanClose` is copied from the item if present; otherwise it defaults to `true`.
- A custom container generator can map per-item capability metadata into `IDockable.DockCapabilityOverrides` for generated windows.
- `IFactory.GetContainerFromItem(object item)` returns the currently tracked generated container for a source item.
- When a generated document or tool is closed, Dock can remove the source item from `ItemsSource` (when it implements `IList`), controlled by `DockSettings.UpdateItemsSourceOnUnregister` and per-dock overrides.
- Source-generated document/tool closes are treated as remove operations, even when `Factory.HideDocumentsOnClose` or `Factory.HideToolsOnClose` is enabled.
Expand Down
5 changes: 5 additions & 0 deletions docfx/articles/dock-manager-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

- The manager centralises all drag-and-drop logic, keeping `DockControl` free from layout code.
- It exposes the `PreventSizeConflicts` property which blocks two fixed-size tools from being docked together.
- It exposes `LastCapabilityEvaluation` so you can inspect policy-based rejections.
- The manager calls back into the factory so your view models are updated consistently.

## Basic usage
Expand Down Expand Up @@ -41,6 +42,8 @@ public sealed class CustomDockManager : IDockManager
public DockPoint Position { get => _inner.Position; set => _inner.Position = value; }
public DockPoint ScreenPosition { get => _inner.ScreenPosition; set => _inner.ScreenPosition = value; }
public bool PreventSizeConflicts { get => _inner.PreventSizeConflicts; set => _inner.PreventSizeConflicts = value; }
public bool IsDockingEnabled { get => _inner.IsDockingEnabled; set => _inner.IsDockingEnabled = value; }
public DockCapabilityEvaluation? LastCapabilityEvaluation => _inner.LastCapabilityEvaluation;

public bool ValidateTool(ITool sourceTool, IDockable target, DragAction action, DockOperation operation, bool execute)
{
Expand All @@ -63,6 +66,8 @@ public sealed class CustomDockManager : IDockManager
}
```

When validation returns `false`, inspect `LastCapabilityEvaluation` to understand policy-driven blocks (root policy, dock policy, or per-dockable override).

Use your `IDockManager` implementation in a custom host control. `DockControl` always constructs its own `DockManager`.

## Guidelines for custom managers
Expand Down
2 changes: 2 additions & 0 deletions docfx/articles/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@
href: dock-targets.md
- name: Docking constraints and layout lock
href: dock-docking-constraints.md
- name: Capability policies and overrides
href: dock-capability-policies.md
- name: Accessibility and UI automation
href: dock-accessibility.md
- name: Floating dock adorners
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Dock.Model.Avalonia.Controls;
using Dock.Model.Core;
using DockXamlReactiveUISample.Models;

namespace DockXamlReactiveUISample.Infrastructure;

Expand All @@ -22,6 +23,8 @@ public override void PrepareDocumentContainer(IItemsSourceDock dock, IDockable c
{
generatedDocument.SourceIndex = index;
}

ApplyCapabilityOverrides(container, item);
}

public override IDockable? CreateToolContainer(IToolItemsSourceDock dock, object item, int index)
Expand All @@ -41,6 +44,31 @@ public override void PrepareToolContainer(IToolItemsSourceDock dock, IDockable c
{
generatedTool.SourceIndex = index;
}

ApplyCapabilityOverrides(container, item);
}

private static void ApplyCapabilityOverrides(IDockable container, object item)
{
var overrides = item switch
{
DocumentItem documentItem => CreateOverrides(documentItem.CloseOverride, documentItem.FloatOverride),
ToolItem toolItem => CreateOverrides(toolItem.CloseOverride, toolItem.FloatOverride),
_ => null
};

container.DockCapabilityOverrides = overrides;
}

private static DockCapabilityOverrides? CreateOverrides(bool? canClose, bool? canFloat)
{
var overrides = new DockCapabilityOverrides
{
CanClose = canClose,
CanFloat = canFloat
};

return overrides.HasAnyOverride ? overrides : null;
}
}

Expand Down
14 changes: 14 additions & 0 deletions samples/DockXamlReactiveUISample/Models/DocumentItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ public class DocumentItem : ReactiveObject
private string _editableContent = string.Empty;
private string _status = string.Empty;
private bool _canClose = true;
private bool? _closeOverride;
private bool? _floatOverride;

public string Title
{
Expand Down Expand Up @@ -39,4 +41,16 @@ public bool CanClose
get => _canClose;
set => this.RaiseAndSetIfChanged(ref _canClose, value);
}

public bool? CloseOverride
{
get => _closeOverride;
set => this.RaiseAndSetIfChanged(ref _closeOverride, value);
}

public bool? FloatOverride
{
get => _floatOverride;
set => this.RaiseAndSetIfChanged(ref _floatOverride, value);
}
}
14 changes: 14 additions & 0 deletions samples/DockXamlReactiveUISample/Models/ToolItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ public class ToolItem : ReactiveObject
private string _description = string.Empty;
private string _status = string.Empty;
private bool _canClose = true;
private bool? _closeOverride;
private bool? _floatOverride;

public string Title
{
Expand All @@ -32,4 +34,16 @@ public bool CanClose
get => _canClose;
set => this.RaiseAndSetIfChanged(ref _canClose, value);
}

public bool? CloseOverride
{
get => _closeOverride;
set => this.RaiseAndSetIfChanged(ref _closeOverride, value);
}

public bool? FloatOverride
{
get => _floatOverride;
set => this.RaiseAndSetIfChanged(ref _floatOverride, value);
}
}
Loading
Loading