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
133 changes: 133 additions & 0 deletions docfx/articles/dock-accessibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Accessibility and UI Automation

Dock includes a dedicated UI automation layer for docking controls. This improves screen reader discoverability and enables automation clients to query dock state and invoke core actions.

## Control coverage

| Control | Peer | Role (`AutomationControlType`) | Providers |
| --- | --- | --- | --- |
| `DockControl` | `DockControlAutomationPeer` | `Pane` | - |
| `RootDockControl` | `RootDockControlAutomationPeer` | `Pane` | - |
| `DockCommandBarHost` | `DockCommandBarHostAutomationPeer` | `ToolBar` | - |
| `DockTarget` / `GlobalDockTarget` | `DockTargetAutomationPeer` | `Pane` | `IInvokeProvider` |
| `DocumentControl` | `DocumentControlAutomationPeer` | `Pane` | `IInvokeProvider` |
| `ToolControl` | `ToolControlAutomationPeer` | `Pane` | `IInvokeProvider` |
| `MdiDocumentControl` | `MdiDocumentControlAutomationPeer` | `Pane` | `IInvokeProvider` |
| `DocumentTabStrip` | `DocumentTabStripAutomationPeer` | `Tab` | `ISelectionProvider`, `IScrollProvider` |
| `ToolTabStrip` | `ToolTabStripAutomationPeer` | `Tab` | `ISelectionProvider`, `IScrollProvider` |
| `DocumentTabStripItem` | `DocumentTabStripItemAutomationPeer` | `TabItem` | `IInvokeProvider`, selection item support |
| `ToolTabStripItem` | `ToolTabStripItemAutomationPeer` | `TabItem` | `IInvokeProvider`, selection item support |
| `ToolChromeControl` | `ToolChromeControlAutomationPeer` | `TitleBar` | `IInvokeProvider`, `IExpandCollapseProvider` |
| `PinnedDockControl` | `PinnedDockControlAutomationPeer` | `Pane` | `IExpandCollapseProvider` |
| `ToolPinnedControl` | `ToolPinnedControlAutomationPeer` | `Tab` | `ISelectionProvider` |
| `ToolPinItemControl` | `ToolPinItemControlAutomationPeer` | `TabItem` | `IInvokeProvider`, `ISelectionItemProvider` |
| `MdiDocumentWindow` | `MdiDocumentWindowAutomationPeer` | `Window` | `IInvokeProvider` |
| `DockSelectorOverlay` | `DockSelectorOverlayAutomationPeer` | `List` | `IExpandCollapseProvider`, `ISelectionProvider`, `IScrollProvider`, `IValueProvider` |
| `HostWindow` | `HostWindowAutomationPeer` | `Window` | `IInvokeProvider` |
| `HostWindowTitleBar` | `HostWindowTitleBarAutomationPeer` | `TitleBar` | `IInvokeProvider` |
| `PinnedDockWindow` | `PinnedDockWindowAutomationPeer` | `Window` | `IInvokeProvider` |
| `DragPreviewControl` | `DragPreviewControlAutomationPeer` | `Pane` | `IValueProvider` |
| `DragPreviewWindow` | `DragPreviewWindowAutomationPeer` | `Pane` | Decorative only (non-control/non-content element) |
| `DockAdornerWindow` | `DockAdornerWindowAutomationPeer` | `Pane` | Decorative only (non-control/non-content element) |

## Provider behavior contract

- `IInvokeProvider` on dock hosts (`DocumentControl`, `ToolControl`, `MdiDocumentControl`), tab items, chrome, and window peers activates/focuses the represented dockable or window.
- `ISelectionItemProvider` on `DocumentTabStripItem` and `ToolTabStripItem` maps selection actions (`Select`, `AddToSelection`) to the same activation path as `Invoke`.
- `IExpandCollapseProvider` on `DockSelectorOverlay`, `ToolChromeControl`, and `PinnedDockControl` controls selector visibility, flyout visibility, and pinned dock expansion.
- `IValueProvider` on `DockSelectorOverlay` and `DragPreviewControl` is read-only and exposes current selected/status text.
- `IScrollProvider` and `ISelectionProvider` on `DockSelectorOverlay` delegate to the internal `PART_ItemsList` list host.

## Name and ID resolution

Dock peers resolve automation metadata in this order:

1. `AutomationProperties.Name` / `AutomationProperties.AutomationId`
2. Dock model fallback (`IDockable.Title`, `IDockable.Id`)
3. Control fallback (for example, `Document tab`, `Dock target`, `Documents selector`)

This keeps behavior theme-independent and works even when custom templates are used.

You can override generated metadata directly in XAML:

```xml
<DocumentTabStripItem
AutomationProperties.Name="Editor tab"
AutomationProperties.AutomationId="editor-tab-primary" />
```

## State exposure

Peers expose state through `HelpText` and provider properties. Examples:

- Dock target: horizontal/vertical/global availability flags
- Dock host controls: layout id, docking enabled state, selector visibility, command bar counts
- Document/tool hosts: visible counts, active item, create/layout metadata
- Tab strips: selected index, item count, orientation and create affordances
- Tab items: selected/active and dockable capabilities
- Tool chrome: active/pinned/floating/maximized/menu state
- Pinned hosts: alignment/display mode, expanded state and visible pinned count
- MDI window: active and `MdiState`
- Selector overlay: open/closed, mode, item count, selected entry
- Drag preview control: preview status and content visibility
- Host/pinned windows: tracked/tool-window/window-state metadata

## Automation events

Dock peers raise automation change events for key transitions:

- `DockSelectorOverlay`: expand/collapse (`ExpandCollapseStateProperty`), selection (`SelectionProperty`), selected value (`ValueProperty`), mode/name (`NameProperty`), and items updates (`ChildrenChanged`).
- `DocumentTabStripItem` and `ToolTabStripItem`: selection state changes (`SelectionItemPatternIdentifiers.IsSelectedProperty`).
- `DragPreviewControl`: status changes (`ValuePatternIdentifiers.ValueProperty`).

## Template requirements

- Keep `PART_ItemsList` (`ListBox`) in `DockSelectorOverlay` templates to preserve full `ISelectionProvider` and `IScrollProvider` behavior for automation readers.

## Actions

Primary actions are automation-invokable where applicable:

- Document/tool/MDI host invoke activates the current (or first visible) dockable.
- Tab peers invoke activation and selection of the represented dockable.
- Pinned tab invoke activates the represented pinned tool.
- Tool chrome invoke activates the active tool; expand/collapse opens and closes the tool flyout.
- Pinned dock expand/collapse toggles `IToolDock.IsExpanded`.
- MDI window invoke activates the represented document window.
- Selector overlay expand/collapse toggles overlay visibility.
- Host and pinned windows invoke to focus/activate their surface.

## Keyboard-only selector navigation

Selector overlay keyboard navigation is validated in headless tests:

- Open document selector: `DockSettings.DocumentSelectorKeyGesture` (default `Ctrl+Tab`)
- Open tool selector: `DockSettings.ToolSelectorKeyGesture` (default `Ctrl+Alt+Tab`)
- Navigate: `Tab`, `Shift+Tab`, arrow keys
- Commit: `Enter` or release selector modifier keys
- Cancel: `Esc`

See [Selector overlay](dock-selector-overlay.md) for usage and runtime customization.

## Testing automation peers

You can inspect peers programmatically:

```csharp
Control control = new DocumentTabStripItem { DataContext = document };
AutomationPeer peer = ControlAutomationPeer.CreatePeerForElement(control);

AutomationControlType role = peer.GetAutomationControlType();
string name = peer.GetName();
IInvokeProvider? invoke = peer.GetProvider<IInvokeProvider>();
invoke?.Invoke();
```

Headless validation in this repository includes:

- `AutomationPeersTests` for role/provider/state contracts.
- `AutomationReaderCompatibilityTests` for peer-tree traversal and automation-reader style pattern usage.
- `DockSelectorKeyboardNavigationTests` for keyboard-only selector workflows.
- `AutomationPeerLeakTests` (Release) to validate event/subscription cleanup and prevent peer-related leaks.

For full control property reference, see [Avalonia controls reference](dock-controls-reference.md).
44 changes: 44 additions & 0 deletions docfx/articles/dock-controls-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ Unless noted otherwise, the properties listed are Avalonia styled properties and
| `SelectedItem` | `DockSelectorItem?` | Currently highlighted item. |
| `Mode` | `DockSelectorMode` | Documents or tools selector mode. |

Template part:
- `PART_ItemsList` (`ListBox`) - selector item host used for selection and scroll automation delegation.

### DockTargetBase (DockTarget, GlobalDockTarget)

| Property | Type | Description |
Expand All @@ -53,6 +56,47 @@ Unless noted otherwise, the properties listed are Avalonia styled properties and

`DockTarget` and `GlobalDockTarget` inherit these properties without adding new ones.

## Accessibility automation peers

Dock provides dedicated automation peers for key interaction controls:

| Control | Peer | Role | Providers |
| --- | --- | --- | --- |
| `DockControl` | `DockControlAutomationPeer` | `Pane` | - |
| `RootDockControl` | `RootDockControlAutomationPeer` | `Pane` | - |
| `DockCommandBarHost` | `DockCommandBarHostAutomationPeer` | `ToolBar` | - |
| `DockTarget` / `GlobalDockTarget` | `DockTargetAutomationPeer` | `Pane` | `IInvokeProvider` |
| `DocumentControl` | `DocumentControlAutomationPeer` | `Pane` | `IInvokeProvider` |
| `ToolControl` | `ToolControlAutomationPeer` | `Pane` | `IInvokeProvider` |
| `MdiDocumentControl` | `MdiDocumentControlAutomationPeer` | `Pane` | `IInvokeProvider` |
| `DocumentTabStrip` | `DocumentTabStripAutomationPeer` | `Tab` | `ISelectionProvider`, `IScrollProvider` |
| `ToolTabStrip` | `ToolTabStripAutomationPeer` | `Tab` | `ISelectionProvider`, `IScrollProvider` |
| `DocumentTabStripItem` | `DocumentTabStripItemAutomationPeer` | `TabItem` | `IInvokeProvider` and selection item support |
| `ToolTabStripItem` | `ToolTabStripItemAutomationPeer` | `TabItem` | `IInvokeProvider` and selection item support |
| `ToolChromeControl` | `ToolChromeControlAutomationPeer` | `TitleBar` | `IInvokeProvider`, `IExpandCollapseProvider` |
| `PinnedDockControl` | `PinnedDockControlAutomationPeer` | `Pane` | `IExpandCollapseProvider` |
| `ToolPinnedControl` | `ToolPinnedControlAutomationPeer` | `Tab` | `ISelectionProvider` |
| `ToolPinItemControl` | `ToolPinItemControlAutomationPeer` | `TabItem` | `IInvokeProvider`, `ISelectionItemProvider` |
| `MdiDocumentWindow` | `MdiDocumentWindowAutomationPeer` | `Window` | `IInvokeProvider` |
| `DockSelectorOverlay` | `DockSelectorOverlayAutomationPeer` | `List` | `IExpandCollapseProvider`, `ISelectionProvider`, `IScrollProvider`, `IValueProvider` |
| `HostWindow` | `HostWindowAutomationPeer` | `Window` | `IInvokeProvider` |
| `HostWindowTitleBar` | `HostWindowTitleBarAutomationPeer` | `TitleBar` | `IInvokeProvider` |
| `PinnedDockWindow` | `PinnedDockWindowAutomationPeer` | `Window` | `IInvokeProvider` |
| `DragPreviewControl` | `DragPreviewControlAutomationPeer` | `Pane` | `IValueProvider` |
| `DragPreviewWindow` | `DragPreviewWindowAutomationPeer` | `Pane` | decorative-only (not exposed as control/content element) |
| `DockAdornerWindow` | `DockAdornerWindowAutomationPeer` | `Pane` | decorative-only (not exposed as control/content element) |

Name and ID values prefer `AutomationProperties`, then Dock model identifiers (`Title`, `Id`) for stable fallback behavior.

Automation integration notes:

- Set `AutomationProperties.Name` and `AutomationProperties.AutomationId` on controls when you need deterministic labels/ids across themes.
- `ISelectionItemProvider.Select` for `DocumentTabStripItem` and `ToolTabStripItem` uses the same activation behavior as `IInvokeProvider.Invoke`.
- `DockSelectorOverlay` automation selection/scroll support depends on the `PART_ItemsList` template part.
- `DragPreviewWindow` and `DockAdornerWindow` peers are intentionally non-interactive and not exposed as control/content elements.

For behavior details and keyboard validation guidance, see [Accessibility and UI automation](dock-accessibility.md).

## Tab, chrome, and tool controls

### DocumentControl
Expand Down
25 changes: 25 additions & 0 deletions docfx/articles/dock-selector-overlay.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,36 @@ The overlay itself is a `DockSelectorOverlay` control in the `DockControl` templ
- `Items` - The `DockSelectorItem` list rendered by the overlay.
- `SelectedItem` - The currently highlighted selector item.
- `Mode` - `Documents` or `Tools`, shown in the header.
- `PART_ItemsList` - `ListBox` template part used for selector navigation and UI automation selection/scroll delegation. Keep this part in custom templates for full reader support.

These properties are primarily used by the template but can be styled or replaced in a custom theme.

## Automation behavior

`DockSelectorOverlayAutomationPeer` exposes:

- `AutomationControlType.List`
- `IExpandCollapseProvider` for open/close
- `ISelectionProvider` for current selector entry
- `IScrollProvider` delegated to the internal `ListBox`
- `IValueProvider` (read-only selected title)

Automation events raised by `DockSelectorOverlayAutomationPeer`:

- `ExpandCollapsePatternIdentifiers.ExpandCollapseStateProperty` when `IsOpen` changes.
- `SelectionPatternIdentifiers.SelectionProperty` and `ValuePatternIdentifiers.ValueProperty` when `SelectedItem` changes.
- `AutomationElementIdentifiers.NameProperty` when `Mode` changes (for mode-specific selector name).
- `ChildrenChanged` when `Items` is replaced.

Reader compatibility notes:

- `IValueProvider.SetValue` is intentionally unsupported (read-only contract).
- Selection and scroll providers are delegated to `PART_ItemsList`, so they stay compatible with default list automation behavior.

## Ordering and selection

The selector is ordered by the most recently activated dockables. Dock tracks activation order inside `DockControl`, so frequently used documents and tools appear first.

For related settings see [Dock settings](dock-settings.md).

For UI automation peer behavior and accessibility contract details, see [Accessibility and UI automation](dock-accessibility.md).
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: Accessibility and UI automation
href: dock-accessibility.md
- name: Floating dock adorners
href: dock-floating-adorners.md
- name: Enable window drag
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
<StackPanel Spacing="8">
<TextBlock Text="{TemplateBinding Mode}"
FontWeight="SemiBold" />
<ListBox ItemsSource="{TemplateBinding Items}"
<ListBox x:Name="PART_ItemsList"
ItemsSource="{TemplateBinding Items}"
SelectedItem="{TemplateBinding SelectedItem}"
Background="Transparent"
BorderThickness="0"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (c) Wiesław Šoltés. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
using Avalonia.Automation;
using Avalonia.Automation.Peers;
using Dock.Avalonia.Controls;

namespace Dock.Avalonia.Automation.Peers;

internal sealed class DockAdornerWindowAutomationPeer : WindowAutomationPeer
{
private readonly DockAdornerWindow _owner;

internal DockAdornerWindowAutomationPeer(DockAdornerWindow owner)
: base(owner)
{
_owner = owner;
}

protected override string GetClassNameCore()
{
return nameof(DockAdornerWindow);
}

protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Pane;
}

protected override string GetNameCore()
{
var baseName = base.GetNameCore();
if (!string.IsNullOrWhiteSpace(baseName))
{
return baseName!;
}

return DockAutomationPeerHelper.ResolveName(_owner, "Dock adorner window");
}

protected override string GetHelpTextCore()
{
return DockAutomationPeerHelper.FormatState(
("Visible", _owner.IsVisible),
("WindowState", _owner.WindowState));
}

protected override bool IsControlElementCore()
{
// Dock adorner visuals are decorative and not user-invokable content.
return false;
}

protected override bool IsContentElementCore()
{
return false;
}
}
Loading
Loading