diff --git a/Dock.slnx b/Dock.slnx
index 97df6aa48..3466da765 100644
--- a/Dock.slnx
+++ b/Dock.slnx
@@ -58,6 +58,7 @@
+
diff --git a/docfx/articles/README.md b/docfx/articles/README.md
index 4ecb4e67c..12f33f353 100644
--- a/docfx/articles/README.md
+++ b/docfx/articles/README.md
@@ -35,6 +35,7 @@ Dock supports a wide range of UI patterns:
- Tool panes that auto-hide, pin, or float.
- Split layouts with proportional sizing and drag handles.
- Floating windows with docking indicators.
+- Managed floating windows hosted inside the main window.
- Persisted layouts that restore across sessions.
## Key features
diff --git a/docfx/articles/dock-floating-adorners.md b/docfx/articles/dock-floating-adorners.md
index c30e897a2..4eace19bb 100644
--- a/docfx/articles/dock-floating-adorners.md
+++ b/docfx/articles/dock-floating-adorners.md
@@ -19,3 +19,5 @@ AppBuilder.Configure()
When enabled `AdornerHelper` creates a lightweight `DockAdornerWindow` positioned above the drag source. The window is transparent and not topmost, so the drag preview window still appears above the adorner because only the preview is marked as `Topmost`.
Use this option if dock targets fail to appear when dragging over native controls or popups. The default value is `false` which uses an `AdornerLayer` inside the same window.
+
+In managed window mode (`DockSettings.UseManagedWindows = true`), the floating adorner is rendered inside `ManagedWindowLayer` instead of a native window.
diff --git a/docfx/articles/dock-host-window-locator.md b/docfx/articles/dock-host-window-locator.md
index c48759429..8130bbb97 100644
--- a/docfx/articles/dock-host-window-locator.md
+++ b/docfx/articles/dock-host-window-locator.md
@@ -41,6 +41,21 @@ windows work without extra setup, but it also overwrites any locators you
configured earlier. Disable `InitializeFactory` if you want to provide your own
locators up front.
+## Managed windows
+
+Dock can host floating windows inside the main window (managed mode). When
+`DockSettings.UseManagedWindows` is enabled, the default locator returns a
+`ManagedHostWindow` instead of a native `HostWindow`. You can still override the
+locator or provide your own window factory via `DockControl.HostWindowFactory`.
+
+Managed windows also require `DockControl.EnableManagedWindowLayer` and a
+`ManagedWindowLayer` template part. See the [Managed windows guide](dock-managed-windows-guide.md)
+for setup details and [Managed windows reference](dock-managed-windows-reference.md)
+for API information.
+
+In managed mode, floating windows are rendered using the MDI layout system, so
+they remain part of the main visual tree and reuse the same theme resources.
+
## Fallback locator
If no entry matches the provided key, `GetHostWindow` calls
diff --git a/docfx/articles/dock-managed-windows-guide.md b/docfx/articles/dock-managed-windows-guide.md
new file mode 100644
index 000000000..f71604165
--- /dev/null
+++ b/docfx/articles/dock-managed-windows-guide.md
@@ -0,0 +1,49 @@
+# Managed Windows Guide
+
+Managed windows host floating docks inside the main window instead of spawning native OS windows. When enabled, Dock uses the in-app MDI layer to render floating windows as `MdiDocumentWindow` controls.
+
+## When to use managed windows
+
+Managed windows are useful when:
+
+- Your app should stay inside a single top-level window.
+- You want consistent window chrome across platforms.
+- Native window restrictions or airspace issues make OS windows undesirable.
+
+The main window is still an OS window. Managed windows affect only floating dock windows.
+
+## How managed windows work
+
+1. `DockSettings.UseManagedWindows` switches floating windows to `ManagedHostWindow`.
+2. `DockControl` registers its `ManagedWindowLayer` with the factory when `EnableManagedWindowLayer` is true.
+3. `ManagedHostWindow` creates a `ManagedDockWindowDocument` that wraps the `IDockWindow` model.
+4. `ManagedWindowLayer` renders managed windows using `MdiLayoutPanel` and `MdiDocumentWindow`.
+
+The managed windows remain in the main visual tree so they can share styles and resources with the rest of the app.
+
+## Interaction parity
+
+Managed windows reuse the same interaction model as native windows:
+
+- Dragging and resizing are handled by `MdiDocumentWindow` and its layout manager.
+- Dock targets, drag previews, and pinned windows are rendered inside the managed layer.
+- Window magnetism and bring-to-front behavior apply within the managed layer.
+
+## Differences from native windows
+
+Managed windows are not OS windows:
+
+- They do not appear in the taskbar or window switchers.
+- They cannot be moved outside the main window or across monitors.
+- Owner relationships and OS-level z-order do not apply; ordering uses `MdiZIndex`.
+
+## Theming and templates
+
+`ManagedWindowLayer` is part of the `DockControl` template and must be named `PART_ManagedWindowLayer`. If you replace the template, include the layer and keep `EnableManagedWindowLayer` set to `true` so floating windows remain visible.
+
+## Related articles
+
+- [Managed windows how-to](dock-managed-windows-howto.md)
+- [Managed windows reference](dock-managed-windows-reference.md)
+- [Floating windows](dock-windows.md)
+- [MDI document layout](dock-mdi.md)
diff --git a/docfx/articles/dock-managed-windows-howto.md b/docfx/articles/dock-managed-windows-howto.md
new file mode 100644
index 000000000..153b942c4
--- /dev/null
+++ b/docfx/articles/dock-managed-windows-howto.md
@@ -0,0 +1,75 @@
+# Managed Windows How-To
+
+This guide walks through enabling managed windows and wiring the managed window layer into your layout.
+
+## Enable managed windows
+
+Set the global flag before creating layouts:
+
+```csharp
+using Dock.Settings;
+
+DockSettings.UseManagedWindows = true;
+```
+
+Or configure it via `AppBuilder`:
+
+```csharp
+using Dock.Settings;
+
+AppBuilder.Configure()
+ .UsePlatformDetect()
+ .UseManagedWindows();
+```
+
+## Ensure the managed layer is present
+
+The built-in Dock themes include a `ManagedWindowLayer` in the `DockControl` template. If you provide a custom template, keep the part and name it `PART_ManagedWindowLayer`.
+
+```xml
+
+```
+
+Custom template snippet:
+
+```xml
+
+```
+
+If you disable `EnableManagedWindowLayer`, managed floating windows will not appear.
+
+## Provide a managed host window (optional)
+
+If you override host window creation, return `ManagedHostWindow` when managed windows are enabled:
+
+```csharp
+dockControl.HostWindowFactory = () => new ManagedHostWindow();
+```
+
+You can also supply a factory mapping through `IFactory.HostWindowLocator` or `IFactory.DefaultHostWindowLocator`.
+
+## Customize managed window layout
+
+`ManagedWindowLayer` uses `ClassicMdiLayoutManager` by default. You can swap it with your own implementation:
+
+```csharp
+managedWindowLayer.LayoutManager = new MyMdiLayoutManager();
+```
+
+## Drag preview and overlays
+
+Drag previews and dock adorners are rendered inside the managed layer:
+
+```csharp
+DockSettings.ShowDockablePreviewOnDrag = true;
+DockSettings.DragPreviewOpacity = 0.7;
+```
+
+When dragging a managed floating window, the window itself moves so no preview overlay is shown.
+
+## Troubleshooting
+
+- Floating windows do not appear: verify `DockSettings.UseManagedWindows` is `true` and `EnableManagedWindowLayer` is enabled.
+- Custom templates: ensure `PART_ManagedWindowLayer` exists in the `DockControl` template.
+- Custom host window factory: return `ManagedHostWindow` when managed mode is enabled.
diff --git a/docfx/articles/dock-managed-windows-reference.md b/docfx/articles/dock-managed-windows-reference.md
new file mode 100644
index 000000000..0c80fe57e
--- /dev/null
+++ b/docfx/articles/dock-managed-windows-reference.md
@@ -0,0 +1,46 @@
+# Managed Windows Reference
+
+This reference summarizes the main settings and types involved in managed window hosting.
+
+## Settings
+
+| Setting | Description |
+| --- | --- |
+| `DockSettings.UseManagedWindows` | Use in-app managed windows for floating dock windows. |
+| `DockSettings.EnableWindowMagnetism` | Snap managed windows to nearby windows when dragging. |
+| `DockSettings.WindowMagnetDistance` | Snap distance in pixels for managed window magnetism. |
+| `DockSettings.BringWindowsToFrontOnDrag` | Activate managed windows when dragging begins. |
+| `DockSettings.ShowDockablePreviewOnDrag` | Render dockable content inside drag previews. |
+| `DockSettings.DragPreviewOpacity` | Opacity for drag previews in managed mode. |
+| `DockSettings.UseOwnerForFloatingWindows` | Applies to native windows only. |
+
+## App builder and options
+
+| API | Description |
+| --- | --- |
+| `AppBuilderExtensions.UseManagedWindows` | Enables managed windows in the app builder. |
+| `DockSettingsOptions.UseManagedWindows` | Nullable option used by `WithDockSettings`. |
+
+## DockControl integration
+
+| API | Description |
+| --- | --- |
+| `DockControl.EnableManagedWindowLayer` | Enables registration and display of the managed layer. |
+| `DockControl.HostWindowFactory` | Override host window creation. Return `ManagedHostWindow` in managed mode. |
+
+## Managed window types
+
+| Type | Description |
+| --- | --- |
+| `ManagedHostWindow` | `IHostWindow` implementation that inserts a managed window into the layer. |
+| `ManagedWindowLayer` | `TemplatedControl` that hosts managed windows and overlays. |
+| `ManagedWindowDock` | Dock used to track managed floating windows. |
+| `ManagedDockWindowDocument` | `IMdiDocument` wrapper around `IDockWindow` with `MdiBounds`, `MdiState`, and `MdiZIndex`. |
+
+## MDI integration
+
+| Type | Description |
+| --- | --- |
+| `MdiDocumentWindow` | Control that renders managed floating windows. |
+| `IMdiLayoutManager` | Strategy for arranging MDI windows. |
+| `ClassicMdiLayoutManager` | Default managed window layout manager. |
diff --git a/docfx/articles/dock-mdi.md b/docfx/articles/dock-mdi.md
index 85c84593c..8938b30db 100644
--- a/docfx/articles/dock-mdi.md
+++ b/docfx/articles/dock-mdi.md
@@ -64,5 +64,6 @@ For details on the built-in layout helpers and defaults see
- The document header contains a drag handle that starts docking operations when you drag it outside the MDI surface.
- When a document is maximized the stored bounds remain unchanged so restore returns to the previous size.
+- Managed floating windows reuse `MdiDocumentWindow` inside `ManagedWindowLayer` when `DockSettings.UseManagedWindows` is enabled. See the [Managed windows guide](dock-managed-windows-guide.md).
For an overview of all guides see the [documentation index](README.md).
diff --git a/docfx/articles/dock-pinned-window.md b/docfx/articles/dock-pinned-window.md
index 806c48016..bd2a1bbea 100644
--- a/docfx/articles/dock-pinned-window.md
+++ b/docfx/articles/dock-pinned-window.md
@@ -9,6 +9,8 @@ DockSettings.UsePinnedDockWindow = true;
When enabled the `PinnedDockControl` places the preview content inside a lightweight `PinnedDockWindow`. The window follows the host layout and closes automatically when the tool is hidden.
+In managed window mode (`DockSettings.UseManagedWindows = true`), pinned windows render inside `ManagedWindowLayer` instead of a native window.
+
## Alignment and orientation
`PinnedDockControl` exposes `PinnedDockAlignment` to control which edge the pinned preview occupies. The default templates bind it to the owning `ToolDock.Alignment`, but you can override it when building custom templates.
diff --git a/docfx/articles/dock-settings.md b/docfx/articles/dock-settings.md
index b7cd47112..b551ce0b3 100644
--- a/docfx/articles/dock-settings.md
+++ b/docfx/articles/dock-settings.md
@@ -97,6 +97,10 @@ The default value is `0.25`.
`DockSettings.UsePinnedDockWindow` shows auto-hidden dockables inside a floating window instead of sliding panels. See [Pinned Dock Window](dock-pinned-window.md) for details.
+## Managed windows
+
+`DockSettings.UseManagedWindows` hosts floating windows inside the main window using the managed window layer. This affects only floating docks; the main window remains native. See [Managed windows guide](dock-managed-windows-guide.md) for details.
+
## Window magnetism
`DockSettings.EnableWindowMagnetism` toggles snapping of floating windows. The snap distance
@@ -173,6 +177,7 @@ AppBuilder.Configure()
.UsePlatformDetect()
.UseFloatingDockAdorner()
.UseOwnerForFloatingWindows()
+ .UseManagedWindows()
.EnableWindowMagnetism()
.SetWindowMagnetDistance(16)
.BringWindowsToFrontOnDrag()
@@ -194,6 +199,7 @@ AppBuilder.Configure()
| `MinimumVerticalDragDistance` | `DockSettings.MinimumVerticalDragDistance` | Vertical drag threshold. |
| `UseFloatingDockAdorner` | `DockSettings.UseFloatingDockAdorner` | Floating adorner window. |
| `UsePinnedDockWindow` | `DockSettings.UsePinnedDockWindow` | Floating pinned dock window. |
+| `UseManagedWindows` | `DockSettings.UseManagedWindows` | Managed floating windows. |
| `UseOwnerForFloatingWindows` | `DockSettings.UseOwnerForFloatingWindows` | Assign owners to floating windows. |
| `EnableWindowMagnetism` | `DockSettings.EnableWindowMagnetism` | Snap floating windows. |
| `WindowMagnetDistance` | `DockSettings.WindowMagnetDistance` | Snap distance in pixels. |
diff --git a/docfx/articles/dock-window-creation-overrides.md b/docfx/articles/dock-window-creation-overrides.md
new file mode 100644
index 000000000..1e63c46dd
--- /dev/null
+++ b/docfx/articles/dock-window-creation-overrides.md
@@ -0,0 +1,265 @@
+# Window Creation Override Analysis
+
+## Scope and goals
+This analysis focuses on every place the code base creates an Avalonia `Window` (or a derived type) and how those creation points can be overridden to support a managed window system or custom window implementations. The goal is to make all window creation paths consistent and easy to override, especially for floating dock windows created via factories.
+
+For practical setup guidance see the [Managed windows guide](dock-managed-windows-guide.md) and [Managed windows how-to](dock-managed-windows-howto.md).
+
+## Current window creation points
+
+### Library defaults
+- `DockControl.InitializeFactory` assigns `HostWindowLocator` and `DefaultHostWindowLocator` to `new HostWindow()` when no factory is provided. This is the primary source of floating window creation for docking. (`src/Dock.Avalonia/Controls/DockControl.axaml.cs`)
+- `HostAdapter.Present` lazily requests a host window via `Factory.GetHostWindow(id)` when an `IDockWindow` is shown. (`src/Dock.Model/Adapters/HostAdapter.cs`)
+- The diagnostics helper creates a debug window directly via `new Window` and does not use a factory or locator. (`src/Dock.Avalonia.Diagnostics/Controls/RootDockDebugExtensions.cs`)
+
+### Internal helper windows (overlay/preview/pinned)
+- `AdornerHelper` creates a floating `DockAdornerWindow` when `DockSettings.UseFloatingDockAdorner` is enabled. (`src/Dock.Avalonia/Internal/AdornerHelper.cs`, `src/Dock.Avalonia/Controls/DockAdornerWindow.axaml.cs`, `src/Dock.Settings/DockSettings.cs`)
+- `DragPreviewHelper` creates and manages a singleton `DragPreviewWindow` for drag previews. (`src/Dock.Avalonia/Internal/DragPreviewHelper.cs`, `src/Dock.Avalonia/Controls/DragPreviewWindow.axaml.cs`)
+- `PinnedDockControl` creates a `PinnedDockWindow` when `DockSettings.UsePinnedDockWindow` is enabled. (`src/Dock.Avalonia/Controls/PinnedDockControl.axaml.cs`, `src/Dock.Avalonia/Controls/PinnedDockWindow.axaml.cs`, `src/Dock.Settings/DockSettings.cs`)
+
+### App/sample entry points
+- Code-only samples set `desktop.MainWindow = new Window { ... }`. (`samples/DockCodeOnlySample/Program.cs`, `samples/DockCodeOnlyMvvmSample/Program.cs`, `samples/DockFluentCodeOnlySample/Program.cs`)
+- XAML samples declare `` roots and code-behind `MainWindow : Window` classes. (multiple `samples/**/MainWindow.axaml*`)
+
+### Model/window separation
+- Floating window instances are `IDockWindow` (model objects) created by `IFactory.CreateDockWindow`. These are not UI `Window` instances but control the `IHostWindow` that is created later. (`src/Dock.Model.Avalonia/Factory.cs` and similar in other model packages)
+
+## Existing extension points
+- `IFactory.HostWindowLocator` and `IFactory.DefaultHostWindowLocator` are the intended customization points for floating window creation. (`src/Dock.Model/FactoryBase.Locator.cs`)
+- `FactoryBase.InitLayout` will create a default `HostWindowLocator` from `DefaultHostWindowLocator` if none was provided. (`src/Dock.Model/FactoryBase.Init.cs`)
+- Custom `IHostWindow` implementations are supported, but most helpers assume an Avalonia `Window`/`TopLevel` underneath.
+
+## Coupling to Avalonia.Window
+These call sites assume concrete `Window` behavior, which means custom host windows should be `Window`-derived (or provide equivalents) to keep features working:
+- Window activation ordering uses `Window.SortWindowsByZOrder` and `Window.Activate`. (`src/Dock.Avalonia/Internal/WindowActivationHelper.cs`)
+- Z-ordering for docking controls uses `Window.SortWindowsByZOrder`. (`src/Dock.Avalonia/Internal/DockHelpers.cs`)
+- Controls expect `TopLevel.GetTopLevel(this)` to be an `IHostWindow` (so host windows must be `TopLevel` at minimum). (`src/Dock.Avalonia/Controls/DockControl.axaml.cs` and related controls)
+- Window drag logic and chrome integrations are specialized for `HostWindow` and `Window`. (`src/Dock.Avalonia/Internal/WindowDragHelper.cs`, `src/Dock.Avalonia/Controls/ToolChromeControl.axaml.cs`, `src/Dock.Avalonia/Controls/DocumentTabStrip.axaml.cs`)
+- Overlay resolution in Avalonia services explicitly checks `HostWindow` to resolve services from the DataContext. (`src/Dock.Model.ReactiveUI.Services.Avalonia/Services/AvaloniaHostServiceResolver.cs`)
+- Pinned dock window hosting assumes a `Window` owner and attaches to `Window` events. (`src/Dock.Avalonia/Controls/PinnedDockControl.axaml.cs`)
+
+## How windows are used at runtime
+This section maps the window lifecycle and the code paths that depend on a real OS `Window` vs a managed in-app window.
+
+### Lifecycle and tracking
+- `IDockWindow` is a model object; `IHostWindow` is the runtime UI host. `HostAdapter.Present` creates/attaches the host and pushes layout, size, and title. (`src/Dock.Model/Adapters/HostAdapter.cs`)
+- `HostWindow` registers itself in `Factory.HostWindows` on open/close and drives `WindowOpened/Closed` events. (`src/Dock.Avalonia/Controls/HostWindow.axaml.cs`)
+- `DockControl` wires the root window to the root dock and raises window lifecycle events when the main window closes. (`src/Dock.Avalonia/Controls/DockControl.axaml.cs`)
+
+### Activation and z-order
+- Global activation uses `Window.SortWindowsByZOrder` and `Window.Activate`. (`src/Dock.Avalonia/Internal/WindowActivationHelper.cs`)
+- Dock control z-order computations assume OS windows and `Window.SortWindowsByZOrder`. (`src/Dock.Avalonia/Internal/DockHelpers.cs`)
+
+### Dragging, resizing, and chrome
+- Floating window dragging uses `HostWindowState` + `BeginMoveDrag` and assumes a concrete `HostWindow`. (`src/Dock.Avalonia/Internal/HostWindowState.cs`, `src/Dock.Avalonia/Controls/HostWindow.axaml.cs`)
+- Tool/document chrome controls attach to `HostWindow` and use OS drag behavior for Windows/macOS, with a `WindowDragHelper` fallback on Linux. (`src/Dock.Avalonia/Controls/ToolChromeControl.axaml.cs`, `src/Dock.Avalonia/Internal/WindowDragHelper.cs`)
+- Managed MDI windows already include drag/resize/min/max logic within `MdiDocumentWindow`, which does not require an OS `Window`. (`src/Dock.Avalonia/Controls/MdiDocumentWindow.axaml.cs`)
+
+### Overlays, diagnostics, and helper windows
+- Debug windows and overlay helpers create their own `Window` instances and rely on `TopLevel` to host overlays. (`src/Dock.Avalonia.Diagnostics/Controls/RootDockDebugExtensions.cs`, `src/Dock.Avalonia.Diagnostics/DockDebugOverlayManager.cs`)
+- Floating adorner, drag preview, and pinned dock windows are implemented as OS windows. (`src/Dock.Avalonia/Internal/AdornerHelper.cs`, `src/Dock.Avalonia/Internal/DragPreviewHelper.cs`, `src/Dock.Avalonia/Controls/PinnedDockControl.axaml.cs`)
+
+### Service resolution and data context
+- Overlay services resolve `HostWindow` and its `DataContext` explicitly. Managed windows must surface equivalent data for overlays/services. (`src/Dock.Model.ReactiveUI.Services.Avalonia/Services/AvaloniaHostServiceResolver.cs`)
+
+## Native vs managed window requirements
+To ensure both OS windows and managed windows behave correctly, the same lifecycle contracts must be satisfied.
+
+### Required capabilities (both modes)
+- **Lifecycle**: `Present`/`Exit` must add/remove the hosted layout and raise window events consistently.
+- **Tracking**: size and position must flow between `IDockWindow` and the host.
+- **Activation**: active window tracking and activation events must match dock state (`ActiveDockable`, focus).
+- **Ownership**: floating windows should respect owner/main window ordering and modal behavior where applicable.
+
+### Native (OS) window specifics
+- Use OS activation/z-order via `Window.SortWindowsByZOrder`, `Window.Activate`.
+- Use OS move/resize via `BeginMoveDrag` and pointer capture.
+- Use owner relationships for modal/float windows when `DockSettings.UseOwnerForFloatingWindows` is enabled.
+
+### Managed (in-app) window specifics
+- Replace OS z-order with a managed ordering (e.g., `MdiZIndex`) and update it on activation.
+- Replace OS drag/resize with MDI logic (already in `MdiDocumentWindow` + `IMdiLayoutManager`).
+- Provide a managed “host layer” that can be queried for current window order and activation state.
+- Bridge data context/service resolution (overlay services should resolve from managed host/root).
+- Ensure managed window templates mirror native window themes (title bar, borders, shadows, resize grips, chrome buttons).
+- Ensure input routing (pointer capture, drag handles, resize grips) mirrors native behavior so managed windows feel identical.
+
+## Gaps and friction points
+- `DockControl.InitializeFactory` overwrites any `HostWindowLocator` or `DefaultHostWindowLocator` that might already be configured on the factory, making it hard to inject custom window types unless `InitializeFactory` is disabled.
+- The diagnostics debug window is hardcoded as `new Window` and cannot be swapped without modifying code.
+- Overlay/preview/pinned windows are hardcoded to `DockAdornerWindow`, `DragPreviewWindow`, and `PinnedDockWindow` with no factory hook.
+- There is no single window factory abstraction shared across DockControl defaults, diagnostics, and other window creation sites.
+- `HostWindowLocator` uses string IDs only; it cannot easily choose a window implementation based on richer context (e.g., tool window vs document window) unless IDs are manually encoded.
+- Several runtime behaviors are hardcoded to OS windows (`HostWindowState`, z-order helpers, debug helpers, adorner/preview/pinned windows) and must be abstracted for managed windows.
+- Overlay services and diagnostics assume `TopLevel`/`Window` roots, which do not exist for managed windows.
+
+## Proposed solutions
+
+### A. Add a host window factory hook to DockControl
+- Introduce a property such as `Func HostWindowFactory` (or `Func HostWindowLocatorFactory`).
+- In `InitializeFactory`, only assign `HostWindowLocator` or `DefaultHostWindowLocator` if they are null, and use `HostWindowFactory` when provided.
+- Consider an overload that provides richer context, such as `Func`, so callers can map to different host window types without string IDs.
+
+### B. Centralize window creation via a shared factory service
+- Add an `IWindowFactory` (or `IHostWindowFactory`) in `Dock.Avalonia` and register a default implementation that returns `HostWindow`.
+- Use this factory in DockControl defaults and in diagnostics (`RootDockDebugExtensions`), with optional overrides via DI or explicit parameters.
+
+### C. Make diagnostics and helper windows overridable
+- Add an overload to `AttachDockDebug` that accepts a `Func` or `Func`.
+- Default to the current behavior when no delegate is provided, keeping compatibility.
+- Provide similar factory hooks for `DockAdornerWindow`, `DragPreviewWindow`, and `PinnedDockWindow` (for example via `DockSettings`, a small `IWindowingServices` interface, or an `AppBuilder` extension).
+
+### D. Managed window implementation (reuse MDI)
+Goal: allow floating windows to be hosted inside the main window (managed/MDI-style) instead of creating OS windows, while preserving existing `IDockWindow` + `IHostWindow` plumbing.
+
+Key idea: reuse the existing MDI system (`IMdiDocument`, `MdiLayoutPanel`, `IMdiLayoutManager`, `MdiDocumentWindow`) as the managed window surface, with a thin adapter so the `IHostWindow` contract can drive it.
+
+Proposed shape:
+- Add a `ManagedHostWindow : IHostWindow` that does **not** derive from `Window`. It inserts a managed “window” control into an in-app layer and mirrors size/position/title to `IMdiDocument` state.
+- Add a `ManagedWindowLayer` (or similar) control that hosts MDI windows inside the main window. This can be an `ItemsControl` + `MdiLayoutPanel` pair, reusing existing `MdiDocumentWindow` templates.
+- Provide a factory switch (`DockSettings.UseManagedWindows` or `IFactory.WindowingMode`) that swaps `HostWindowLocator`/`DefaultHostWindowLocator` from `HostWindow` to `ManagedHostWindow`.
+- Adapt the MDI window control to be less `IDock`-specific:
+ - Either introduce a small `IMdiHost` interface (ActiveItem/Items/InvalidateLayout) and use it instead of `IDock`.
+ - Or provide a lightweight `ManagedWindowDock : IDock` implementation in `Dock.Avalonia` for the managed layer, so existing `MdiDocumentWindow` logic keeps working without major changes.
+
+#### Managed window details (from analysis)
+- **Reusable MDI components**: `IMdiDocument`, `MdiLayoutPanel`, `IMdiLayoutManager`, and `ClassicMdiLayoutManager` are already generic and can be reused as-is. (`src/Dock.Avalonia/Mdi/*`, `src/Dock.Model/Core/IMdiDocument.cs`)
+- **Current coupling**: `MdiDocumentWindow` implements drag/resize/min/max logic, but assumes `IMdiDocument.Owner is IDock` and uses `IDock.ActiveDockable` for active state. (`src/Dock.Avalonia/Controls/MdiDocumentWindow.axaml.cs`)
+
+#### Refactors needed for reuse
+- **Decouple host assumptions**: introduce a small host contract (for example `IMdiHost` with `ActiveItem`, `Items`, and `InvalidateLayout`) or provide an adapter dock used only by managed windows.
+- **Managed window layer**: add a `ManagedWindowLayer` control (standalone or inside `DockControl`) to host managed windows inside the main window.
+- **Managed host implementation**: create an `IHostWindow` implementation that inserts a managed window control into the layer rather than spawning an OS window.
+
+#### Minimal concrete approach
+1. Create `ManagedWindowDock : IDock` (or a lighter `IMdiHost`) in `Dock.Avalonia` to own managed windows and track `ActiveDockable`. This allows `MdiDocumentWindow` to keep working with minimal changes.
+2. Create `ManagedHostWindow : IHostWindow` that:
+ - Wraps a managed dock window model that implements `IMdiDocument`.
+ - On `Present`, inserts a `MdiDocumentWindow` into the `ManagedWindowLayer`.
+ - On `Exit`, removes the managed window from the layer.
+ - Maps `IDockWindow` bounds to `IMdiDocument.MdiBounds` (and back on save).
+3. Add a factory hook to choose managed vs native windows:
+ - `HostWindowLocator` / `DefaultHostWindowLocator` returns `ManagedHostWindow` when managed mode is enabled.
+ - A `DockSettings` flag or `IFactory.WindowingMode` (`Native | Managed`) selects the path.
+
+#### Why this fits managed windows
+- Managed windows render inside the main window (no OS window), and the MDI layout manager already provides drag/resize/min/max and z-ordering.
+- The standard floating-window pipeline (`IDockWindow` + `IHostWindow`) remains intact, so app code does not need to change.
+
+## Detailed work required for native + managed parity
+This list captures the additional refactors needed to ensure both window systems behave consistently.
+
+### Window lifecycle abstraction
+- Introduce a small abstraction layer (for example `IWindowingServices`) that exposes:
+ - Create host window (native/managed)
+ - Activate window / bring to front
+ - Z-order query/update
+ - Optional owner/parent relationships
+- Update `WindowActivationHelper` and `DockHelpers` to use this abstraction instead of `Window.SortWindowsByZOrder`.
+
+### Host state and drag handling
+- Extend the existing `IHostWindowState` contract with a managed implementation (or provide a managed `HostWindowState` variant) so both native and managed hosts can drive the same docking events.
+- For managed windows, reuse `MdiDocumentWindow` drag/resize handling and ensure it raises the same docking events (`WindowMoveDragBegin/Move/End`).
+
+### Overlay and diagnostics compatibility
+- Refactor `AvaloniaHostServiceResolver` to resolve services from a managed host layer as well as `HostWindow`.
+- Add factory hooks for debug/overlay windows to allow managed equivalents or in-tree overlays.
+
+### Helper windows
+- Add explicit creation hooks for `DockAdornerWindow`, `DragPreviewWindow`, and `PinnedDockWindow`, and provide managed equivalents where appropriate.
+- Ensure helper windows can attach to either a `TopLevel` or a managed host layer.
+- Provide managed counterparts that can reuse the same styling resources as native windows.
+
+### Data context and layout ownership
+- Managed host windows must expose a data context path for overlays and document tooling that currently assume `HostWindow`.
+- Maintain the owner chain and active dockable in managed mode (either via `IMdiHost` or `ManagedWindowDock`).
+
+## Managed window theming and template parity
+Managed windows should look and feel like real windows. The goal is to reuse existing window themes (Fluent/Simple) and chrome resources so managed substitutes are visually consistent and require minimal additional styling.
+
+### Theming goals
+- Reuse existing `HostWindow` and window chrome resources where possible.
+- Share title bar, button, and border templates between native and managed windows.
+- Keep overlay/preview/pinned managed windows consistent with app themes.
+- Support the same pseudo-classes (`:active`, `:maximized`, `:minimized`, `:dragging`) for consistent styling.
+
+### Template reuse strategy
+- Extract common window chrome into reusable control themes or styles (for example `WindowChromeTheme`, `TitleBarTheme`, `WindowButtonTheme`) that can be applied by both `HostWindow` and managed window controls (or expose common brush keys that both templates consume).
+- Ensure `MdiDocumentWindow` and managed helper windows (adorner/preview/pinned) use the same resource keys as `HostWindow` templates.
+- Avoid duplicating theme XAML by referencing shared resources in `Dock.Avalonia.Themes.*` (Fluent/Simple).
+
+### Theme resource locations (current)
+- `DockFluentTheme.axaml` includes window-related templates from `src/Dock.Avalonia.Themes.Fluent/Controls/*.axaml` (for example `HostWindow.axaml`, `HostWindowTitleBar.axaml`, `DragPreviewWindow.axaml`, `PinnedDockWindow.axaml`, `DockAdornerWindow.axaml`, `MdiDocumentWindow.axaml`, `ManagedWindowLayer.axaml`, `WindowChromeResources.axaml`).
+- `DockSimpleTheme.axaml` includes the same `/Controls/*.axaml` resources; the Simple theme links Fluent control resources via `Dock.Avalonia.Themes.Simple.csproj` (see `AvaloniaResource` link to `Dock.Avalonia.Themes.Fluent/Controls`).
+- New managed-window templates/resources should be added to `src/Dock.Avalonia.Themes.Fluent/Controls/` and referenced in both `DockFluentTheme.axaml` and `DockSimpleTheme.axaml`.
+
+### Managed substitutes that need templates
+- **Managed host surface**: the managed window surface is the existing `MdiDocumentWindow` hosted by `ManagedWindowLayer`; no separate `ManagedHostWindowControl` is required unless future design calls for it.
+- **Managed dock adorner overlay**: overlay-hosted `DockTarget`/`GlobalDockTarget` visuals should reuse the same brush keys as window chrome where applicable.
+- **Managed drag preview host**: `DragPreviewControl` overlays should use the same theme resources as the native preview window.
+- **Managed pinned dock host**: `ToolDockControl` overlays should use the same theme resources as the native pinned dock window.
+- **Managed debug/diagnostic window** (optional): if added later, reuse the same window chrome resource keys for parity.
+
+### Theme integration checklist
+- Define shared resource keys for window chrome (background, border, shadow, title bar, buttons).
+- Apply those keys in both native `HostWindow` templates and managed window controls.
+- Provide theme resources for managed helper windows in `Dock.Avalonia.Themes.Fluent` and `Dock.Avalonia.Themes.Simple`.
+- Verify visual parity across light/dark variants and scaling.
+- Verify pointer hit targets, padding, and resize grip thickness match native windows.
+
+## App and sample guidance
+- Document a supported pattern for custom host windows:
+ - Set `Factory.DefaultHostWindowLocator = () => new MyHostWindow();`
+ - Disable `DockControl.InitializeFactory` if needed to avoid overrides.
+- Provide at least one sample showing custom host windows (for example, a managed-window subclass or a themed host window).
+
+## Backward compatibility
+- Preserve existing defaults when no custom factory/locator is supplied.
+- Introduce new properties/overloads instead of changing existing signatures.
+
+## Suggested implementation steps
+This is a concise summary. Use the checklist below as the source of truth for execution.
+
+1. Add a `HostWindowFactory` (or similar) property to `DockControl` and update `InitializeFactory` to respect existing locators and custom factories.
+2. Add an optional factory parameter to `RootDockDebugExtensions.AttachDockDebug`.
+3. Add creation hooks for `DockAdornerWindow`, `DragPreviewWindow`, and `PinnedDockWindow` (factory delegate or service).
+4. Implement managed window hosting (MDI reuse) via `ManagedWindowLayer` + `ManagedHostWindow`.
+5. Abstract activation/z-order/drag operations so managed windows can participate without `Window.SortWindowsByZOrder`.
+6. Add managed-aware service resolution for overlays/diagnostics.
+7. Extract shared chrome resources and apply them to managed window templates (host/adorner/preview/pinned/debug).
+8. Update docs and samples to demonstrate managed windows and custom host windows with theme parity.
+
+## Implementation plan (checkable tasks)
+1. [x] Add managed window mode flag (`DockSettings.UseManagedWindows` or `IFactory.WindowingMode`) and document default behavior.
+2. [x] Create `ManagedWindowLayer` control to host MDI windows in-app.
+3. [x] Add `ManagedHostWindow : IHostWindow` that maps `IDockWindow` to a managed MDI window item.
+4. [x] Wire `HostWindowLocator`/`DefaultHostWindowLocator` to return `ManagedHostWindow` when managed mode is enabled.
+5. [x] Update `MdiDocumentWindow` dependencies:
+ - Option A: introduce `IMdiHost` and refactor to use it.
+ - Option B: add a `ManagedWindowDock : IDock` implementation used by `ManagedWindowLayer`.
+6. [x] Add factory hooks for `DockAdornerWindow`, `DragPreviewWindow`, and `PinnedDockWindow`.
+7. [x] Add overloads/DI hooks for `RootDockDebugExtensions.AttachDockDebug`.
+8. [x] Add abstraction for activation/z-order so managed windows can be ordered/activated without `Window.SortWindowsByZOrder`.
+9. [x] Make overlay/service resolution work for managed windows (no `TopLevel`/`HostWindow`).
+10. [x] Define shared window chrome resources in `src/Dock.Avalonia.Themes.Fluent/Controls/*.axaml` and include them in `DockFluentTheme.axaml`.
+11. [x] Ensure `DockSimpleTheme.axaml` includes the same resources (linked from Fluent controls) and validate Simple theme overrides.
+12. [x] Apply shared chrome resources to managed windows (host, adorner, drag preview, pinned dock, debug).
+13. [x] Update docs (`dock-window-creation-overrides.md`, `dock-host-window-locator.md`) with managed window guidance and theming notes.
+14. [x] Add/update a sample showing managed window hosting (MDI-backed floating windows) with theme parity.
+15. [ ] Validate: drag/resize, activation, z-order, docking/undocking, theming consistency, input routing, and cleanup on window close.
+
+## Reference locations
+- `src/Dock.Avalonia/Controls/DockControl.axaml.cs`
+- `src/Dock.Model/FactoryBase.Locator.cs`
+- `src/Dock.Model/FactoryBase.Init.cs`
+- `src/Dock.Model/Adapters/HostAdapter.cs`
+- `src/Dock.Avalonia.Diagnostics/Controls/RootDockDebugExtensions.cs`
+- `src/Dock.Avalonia/Internal/AdornerHelper.cs`
+- `src/Dock.Avalonia/Internal/DragPreviewHelper.cs`
+- `src/Dock.Avalonia/Controls/PinnedDockControl.axaml.cs`
+- `src/Dock.Avalonia/Internal/WindowActivationHelper.cs`
+- `src/Dock.Avalonia/Internal/DockHelpers.cs`
+- `src/Dock.Avalonia/Internal/WindowDragHelper.cs`
+- `src/Dock.Model.ReactiveUI.Services.Avalonia/Services/AvaloniaHostServiceResolver.cs`
+- `samples/*/Program.cs`
+- `samples/**/MainWindow.axaml*`
diff --git a/docfx/articles/dock-window-drag.md b/docfx/articles/dock-window-drag.md
index 43eea6a80..0843b8e48 100644
--- a/docfx/articles/dock-window-drag.md
+++ b/docfx/articles/dock-window-drag.md
@@ -24,6 +24,10 @@ The same property is available on the Avalonia control `DocumentDock` and can al
With the property enabled, `DocumentTabStrip` listens for pointer events on its background and initiates a window drag on the surrounding `HostWindow` (or window). The user can grab the tab area and drag the entire window.
+## Managed windows
+
+In managed window mode (`DockSettings.UseManagedWindows = true`), floating windows are rendered inside the main window. Their drag behavior is provided by the managed window chrome (`MdiDocumentWindow`), not by `DocumentTabStrip`. `EnableWindowDrag` remains useful for dragging the main window or native floating windows.
+
## Scenarios
- **Floating windows** – Users can drag the tab bar of a floating document window to reposition it without relying on the window title bar.
diff --git a/docfx/articles/dock-window-owner.md b/docfx/articles/dock-window-owner.md
index 9895b4977..06074bfcf 100644
--- a/docfx/articles/dock-window-owner.md
+++ b/docfx/articles/dock-window-owner.md
@@ -17,3 +17,5 @@ AppBuilder.Configure()
```
When enabled Dock sets the main window as the owner for floating windows, preventing them from appearing behind it. Disable this if you want windows to be independent.
+
+Managed windows do not use OS-level owners, so this setting applies to native floating windows only.
diff --git a/docfx/articles/dock-windows.md b/docfx/articles/dock-windows.md
index 30fe67d49..8ac1a5c17 100644
--- a/docfx/articles/dock-windows.md
+++ b/docfx/articles/dock-windows.md
@@ -24,6 +24,14 @@ Calling `FloatDockable` on the factory opens a dockable in a new window. The new
To customize the platform window (`IHostWindow`) used by floating docks, use `HostWindowLocator` or `DefaultHostWindowLocator`. See [Host window locators](dock-host-window-locator.md) for details.
+## Managed windows
+
+When `DockSettings.UseManagedWindows` is enabled, floating windows are hosted inside the main window instead of spawning native OS windows. The default host window becomes `ManagedHostWindow`, which renders floating windows inside `ManagedWindowLayer` using the MDI layout system.
+
+If you override host window creation, return `ManagedHostWindow` when managed windows are enabled. `DockControl.EnableManagedWindowLayer` must remain `true` for managed windows to appear.
+
+For setup details see the [Managed windows guide](dock-managed-windows-guide.md) and [Managed windows how-to](dock-managed-windows-howto.md).
+
## IDockWindow model members
`IDockWindow` represents the floating window model and includes:
@@ -98,12 +106,12 @@ This behavior is controlled by two settings on `DockSettings`:
When magnetism is enabled, `HostWindow` compares its position against other tracked windows during a drag
and adjusts the position if it falls within the snap distance. This makes it easy to align multiple floating
-windows.
+windows. In managed mode, the same logic applies to managed floating windows within the managed layer.
## Bringing windows to front
If `DockSettings.BringWindowsToFrontOnDrag` is enabled, initiating a drag will activate
all floating windows and any main window hosting a `DockControl` so they stay above other
-applications until the drag completes.
+applications until the drag completes. In managed mode, this updates managed z-order so windows stay above their peers.
For more advanced scenarios see [Adapter Classes](dock-adapters.md) and the [Advanced Guide](dock-advanced.md).
diff --git a/docfx/articles/toc.yml b/docfx/articles/toc.yml
index 2532d709e..af2e3abd6 100644
--- a/docfx/articles/toc.yml
+++ b/docfx/articles/toc.yml
@@ -20,6 +20,8 @@
href: dock-control-initialization.md
- name: Programmatic docking
href: dock-programmatic-docking.md
+ - name: Managed windows how-to
+ href: dock-managed-windows-howto.md
- name: DockManager guide
href: dock-manager-guide.md
- name: API scenarios
@@ -36,6 +38,8 @@
href: dock-mdi.md
- name: MDI layout helpers
href: dock-mdi-layout-helpers.md
+ - name: Managed windows guide
+ href: dock-managed-windows-guide.md
- name: Dock state guide
href: dock-state.md
- name: RestoreDockable behavior
@@ -166,6 +170,8 @@
href: dock-layout-panels.md
- name: Dock settings
href: dock-settings.md
+ - name: Managed windows reference
+ href: dock-managed-windows-reference.md
- name: Dock properties
href: dock-properties.md
- name: DockSettings in controls
diff --git a/samples/DockCodeOnlySample/Program.cs b/samples/DockCodeOnlySample/Program.cs
index 07ea7e856..8a0116d02 100644
--- a/samples/DockCodeOnlySample/Program.cs
+++ b/samples/DockCodeOnlySample/Program.cs
@@ -9,6 +9,7 @@
using Dock.Model.Avalonia;
using Dock.Model.Avalonia.Controls;
using Dock.Model.Core;
+using Dock.Settings;
namespace DockCodeOnlySample;
@@ -23,7 +24,8 @@ static void Main(string[] args)
static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure()
.UsePlatformDetect()
- .LogToTrace();
+ .LogToTrace()
+ .UseManagedWindows();
}
public class App : Application
diff --git a/samples/DockInpcSample/ViewModels/DockFactory.cs b/samples/DockInpcSample/ViewModels/DockFactory.cs
index 60b1c6d10..7679ee044 100644
--- a/samples/DockInpcSample/ViewModels/DockFactory.cs
+++ b/samples/DockInpcSample/ViewModels/DockFactory.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Dock.Avalonia.Controls;
+using Dock.Settings;
using Dock.Model.Controls;
using Dock.Model.Core;
using Dock.Model.Inpc;
@@ -190,7 +191,7 @@ public override void InitLayout(IDockable layout)
HostWindowLocator = new Dictionary>
{
- [nameof(IDockWindow)] = () => new HostWindow()
+ [nameof(IDockWindow)] = () => DockSettings.UseManagedWindows ? new ManagedHostWindow() : new HostWindow()
};
base.InitLayout(layout);
diff --git a/samples/DockMvvmSample/ViewModels/DockFactory.cs b/samples/DockMvvmSample/ViewModels/DockFactory.cs
index cfd46d62d..f676a3fba 100644
--- a/samples/DockMvvmSample/ViewModels/DockFactory.cs
+++ b/samples/DockMvvmSample/ViewModels/DockFactory.cs
@@ -7,6 +7,7 @@
using DockMvvmSample.ViewModels.Tools;
using DockMvvmSample.ViewModels.Views;
using Dock.Avalonia.Controls;
+using Dock.Settings;
using Dock.Model.Controls;
using Dock.Model.Core;
using Dock.Model.Mvvm;
@@ -197,7 +198,7 @@ public override void InitLayout(IDockable layout)
HostWindowLocator = new Dictionary>
{
- [nameof(IDockWindow)] = () => new HostWindow()
+ [nameof(IDockWindow)] = () => DockSettings.UseManagedWindows ? new ManagedHostWindow() : new HostWindow()
};
base.InitLayout(layout);
diff --git a/samples/DockPrismSample/ViewModels/DockFactory.cs b/samples/DockPrismSample/ViewModels/DockFactory.cs
index 7f1da0549..2c0b265a1 100644
--- a/samples/DockPrismSample/ViewModels/DockFactory.cs
+++ b/samples/DockPrismSample/ViewModels/DockFactory.cs
@@ -7,6 +7,7 @@
using DockPrismSample.ViewModels.Tools;
using DockPrismSample.ViewModels.Views;
using Dock.Avalonia.Controls;
+using Dock.Settings;
using Dock.Model.Controls;
using Dock.Model.Core;
using Dock.Model.Prism;
@@ -210,7 +211,7 @@ public override void InitLayout(IDockable layout)
HostWindowLocator = new Dictionary>
{
- [nameof(IDockWindow)] = () => new HostWindow()
+ [nameof(IDockWindow)] = () => DockSettings.UseManagedWindows ? new ManagedHostWindow() : new HostWindow()
};
base.InitLayout(layout);
diff --git a/samples/DockReactivePropertySample/ViewModels/DockFactory.cs b/samples/DockReactivePropertySample/ViewModels/DockFactory.cs
index d953df06d..f14891b02 100644
--- a/samples/DockReactivePropertySample/ViewModels/DockFactory.cs
+++ b/samples/DockReactivePropertySample/ViewModels/DockFactory.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Dock.Avalonia.Controls;
+using Dock.Settings;
using Dock.Model.Controls;
using Dock.Model.Core;
using Dock.Model.ReactiveProperty;
@@ -190,7 +191,7 @@ public override void InitLayout(IDockable layout)
HostWindowLocator = new Dictionary>
{
- [nameof(IDockWindow)] = () => new HostWindow()
+ [nameof(IDockWindow)] = () => DockSettings.UseManagedWindows ? new ManagedHostWindow() : new HostWindow()
};
base.InitLayout(layout);
diff --git a/samples/DockReactiveUICanonicalSample/ViewModels/DockFactory.cs b/samples/DockReactiveUICanonicalSample/ViewModels/DockFactory.cs
index 5dcf7b5dc..3494ae2c7 100644
--- a/samples/DockReactiveUICanonicalSample/ViewModels/DockFactory.cs
+++ b/samples/DockReactiveUICanonicalSample/ViewModels/DockFactory.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Dock.Avalonia.Controls;
+using Dock.Settings;
using Dock.Model.Controls;
using Dock.Model.Core;
using Dock.Model.ReactiveUI;
@@ -140,7 +141,7 @@ public override void InitLayout(IDockable layout)
{
HostWindowLocator = new Dictionary>
{
- [nameof(IDockWindow)] = () => new HostWindow()
+ [nameof(IDockWindow)] = () => DockSettings.UseManagedWindows ? new ManagedHostWindow() : new HostWindow()
};
base.InitLayout(layout);
diff --git a/samples/DockReactiveUICanonicalSample/ViewModels/Workspace/WorkspaceDockFactory.cs b/samples/DockReactiveUICanonicalSample/ViewModels/Workspace/WorkspaceDockFactory.cs
index 95f33aad9..38a7713e4 100644
--- a/samples/DockReactiveUICanonicalSample/ViewModels/Workspace/WorkspaceDockFactory.cs
+++ b/samples/DockReactiveUICanonicalSample/ViewModels/Workspace/WorkspaceDockFactory.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Dock.Avalonia.Controls;
+using Dock.Settings;
using Dock.Model.Controls;
using Dock.Model.Core;
using Dock.Model.ReactiveUI;
@@ -43,7 +44,7 @@ public override void InitLayout(IDockable layout)
{
HostWindowLocator = new Dictionary>
{
- [nameof(IDockWindow)] = () => new HostWindow()
+ [nameof(IDockWindow)] = () => DockSettings.UseManagedWindows ? new ManagedHostWindow() : new HostWindow()
};
base.InitLayout(layout);
diff --git a/samples/DockReactiveUIManagedSample/App.axaml b/samples/DockReactiveUIManagedSample/App.axaml
new file mode 100644
index 000000000..ff7b7befc
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/App.axaml
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #EFEFEF
+ #EFEFEF
+ #EFEFEF
+ #212121
+ #212121
+ #33323232
+ #33323232
+ #FFFAFAFA
+ #E2E2E2
+
+
+ #2F2F2F
+ #2F2F2F
+ #2F2F2F
+ #FFFFFF
+ #FFFFFF
+ #434343
+ #434343
+ #FF212121
+ #1F1F1F
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/DockReactiveUIManagedSample/App.axaml.cs b/samples/DockReactiveUIManagedSample/App.axaml.cs
new file mode 100644
index 000000000..bd96bb4b9
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/App.axaml.cs
@@ -0,0 +1,79 @@
+using System.Diagnostics.CodeAnalysis;
+using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Input;
+using Avalonia.Markup.Xaml;
+using Dock.Avalonia.Diagnostics.Controls;
+using Dock.Avalonia.Diagnostics;
+using DockReactiveUIManagedSample.Themes;
+using DockReactiveUIManagedSample.ViewModels;
+using DockReactiveUIManagedSample.Views;
+
+namespace DockReactiveUIManagedSample;
+
+[RequiresUnreferencedCode("Requires unreferenced code for MainWindowViewModel.")]
+[RequiresDynamicCode("Requires unreferenced code for MainWindowViewModel.")]
+public class App : Application
+{
+ public static IThemeManager? ThemeManager;
+
+ public override void Initialize()
+ {
+ ThemeManager = new FluentThemeManager();
+
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public override void OnFrameworkInitializationCompleted()
+ {
+ // DockManager.s_enableSplitToWindow = true;
+
+ var mainWindowViewModel = new MainWindowViewModel();
+
+ switch (ApplicationLifetime)
+ {
+ case IClassicDesktopStyleApplicationLifetime desktopLifetime:
+ {
+ var mainWindow = new MainWindow
+ {
+ DataContext = mainWindowViewModel
+ };
+#if DEBUG
+ mainWindow.AttachDockDebug(
+ () => mainWindowViewModel.Layout!,
+ new KeyGesture(Key.F11));
+ mainWindow.AttachDockDebugOverlay(new KeyGesture(Key.F9));
+#endif
+ mainWindow.Closing += (_, _) =>
+ {
+ mainWindowViewModel.CloseLayout();
+ };
+
+ desktopLifetime.MainWindow = mainWindow;
+
+ desktopLifetime.Exit += (_, _) =>
+ {
+ mainWindowViewModel.CloseLayout();
+ };
+
+ break;
+ }
+ case ISingleViewApplicationLifetime singleViewLifetime:
+ {
+ var mainView = new MainView()
+ {
+ DataContext = mainWindowViewModel
+ };
+
+ singleViewLifetime.MainView = mainView;
+
+ break;
+ }
+ }
+
+ base.OnFrameworkInitializationCompleted();
+#if DEBUG
+ this.AttachDevTools();
+#endif
+ }
+}
diff --git a/samples/DockReactiveUIManagedSample/DockReactiveUIManagedSample.csproj b/samples/DockReactiveUIManagedSample/DockReactiveUIManagedSample.csproj
new file mode 100644
index 000000000..1c541c8c5
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/DockReactiveUIManagedSample.csproj
@@ -0,0 +1,41 @@
+
+
+
+ net10.0
+ WinExe
+ False
+ False
+ enable
+ OnlyProperties
+ true
+ $(BaseIntermediateOutputPath)\GeneratedFiles
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/DockReactiveUIManagedSample/Models/DemoData.cs b/samples/DockReactiveUIManagedSample/Models/DemoData.cs
new file mode 100644
index 000000000..66d562b04
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/Models/DemoData.cs
@@ -0,0 +1,6 @@
+
+namespace DockReactiveUIManagedSample.Models;
+
+public class DemoData
+{
+}
diff --git a/samples/DockReactiveUIManagedSample/Models/Documents/DemoDocument.cs b/samples/DockReactiveUIManagedSample/Models/Documents/DemoDocument.cs
new file mode 100644
index 000000000..f20ab6df0
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/Models/Documents/DemoDocument.cs
@@ -0,0 +1,6 @@
+
+namespace DockReactiveUIManagedSample.Models.Documents;
+
+public class DemoDocument
+{
+}
diff --git a/samples/DockReactiveUIManagedSample/Models/Tools/Tool1.cs b/samples/DockReactiveUIManagedSample/Models/Tools/Tool1.cs
new file mode 100644
index 000000000..ca5226379
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/Models/Tools/Tool1.cs
@@ -0,0 +1,6 @@
+
+namespace DockReactiveUIManagedSample.Models.Tools;
+
+public class Tool1
+{
+}
diff --git a/samples/DockReactiveUIManagedSample/Models/Tools/Tool2.cs b/samples/DockReactiveUIManagedSample/Models/Tools/Tool2.cs
new file mode 100644
index 000000000..7e81b9fe4
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/Models/Tools/Tool2.cs
@@ -0,0 +1,6 @@
+
+namespace DockReactiveUIManagedSample.Models.Tools;
+
+public class Tool2
+{
+}
diff --git a/samples/DockReactiveUIManagedSample/Models/Tools/Tool3.cs b/samples/DockReactiveUIManagedSample/Models/Tools/Tool3.cs
new file mode 100644
index 000000000..7337a9311
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/Models/Tools/Tool3.cs
@@ -0,0 +1,6 @@
+
+namespace DockReactiveUIManagedSample.Models.Tools;
+
+public class Tool3
+{
+}
diff --git a/samples/DockReactiveUIManagedSample/Models/Tools/Tool4.cs b/samples/DockReactiveUIManagedSample/Models/Tools/Tool4.cs
new file mode 100644
index 000000000..ab54d045e
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/Models/Tools/Tool4.cs
@@ -0,0 +1,6 @@
+
+namespace DockReactiveUIManagedSample.Models.Tools;
+
+public class Tool4
+{
+}
diff --git a/samples/DockReactiveUIManagedSample/Models/Tools/Tool5.cs b/samples/DockReactiveUIManagedSample/Models/Tools/Tool5.cs
new file mode 100644
index 000000000..495844c12
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/Models/Tools/Tool5.cs
@@ -0,0 +1,6 @@
+
+namespace DockReactiveUIManagedSample.Models.Tools;
+
+public class Tool5
+{
+}
diff --git a/samples/DockReactiveUIManagedSample/Models/Tools/Tool6.cs b/samples/DockReactiveUIManagedSample/Models/Tools/Tool6.cs
new file mode 100644
index 000000000..82cf1c3e7
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/Models/Tools/Tool6.cs
@@ -0,0 +1,6 @@
+
+namespace DockReactiveUIManagedSample.Models.Tools;
+
+public class Tool6
+{
+}
diff --git a/samples/DockReactiveUIManagedSample/Models/Tools/Tool7.cs b/samples/DockReactiveUIManagedSample/Models/Tools/Tool7.cs
new file mode 100644
index 000000000..f4058ca3f
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/Models/Tools/Tool7.cs
@@ -0,0 +1,6 @@
+
+namespace DockReactiveUIManagedSample.Models.Tools;
+
+public class Tool7
+{
+}
diff --git a/samples/DockReactiveUIManagedSample/Models/Tools/Tool8.cs b/samples/DockReactiveUIManagedSample/Models/Tools/Tool8.cs
new file mode 100644
index 000000000..4c0d7a8e5
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/Models/Tools/Tool8.cs
@@ -0,0 +1,6 @@
+
+namespace DockReactiveUIManagedSample.Models.Tools;
+
+public class Tool8
+{
+}
diff --git a/samples/DockReactiveUIManagedSample/Program.cs b/samples/DockReactiveUIManagedSample/Program.cs
new file mode 100644
index 000000000..2bf34a21c
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/Program.cs
@@ -0,0 +1,30 @@
+// 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;
+using ReactiveUI.Avalonia;
+using System;
+using System.Diagnostics.CodeAnalysis;
+using Dock.Settings;
+
+namespace DockReactiveUIManagedSample;
+
+[RequiresUnreferencedCode("Requires unreferenced code for App.")]
+[RequiresDynamicCode("Requires unreferenced code for App.")]
+internal class Program
+{
+ [STAThread]
+ private static void Main(string[] args)
+ {
+ BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
+ }
+
+ public static AppBuilder BuildAvaloniaApp()
+ => AppBuilder.Configure()
+ .UsePlatformDetect()
+ .WithInterFont()
+ .UseReactiveUI()
+ .UseManagedWindows()
+ .ShowDockablePreviewOnDrag()
+ .SetDragPreviewOpacity(0.6)
+ .LogToTrace();
+}
diff --git a/samples/DockReactiveUIManagedSample/Themes/FluentThemeManager.cs b/samples/DockReactiveUIManagedSample/Themes/FluentThemeManager.cs
new file mode 100644
index 000000000..a6925fe95
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/Themes/FluentThemeManager.cs
@@ -0,0 +1,22 @@
+using Avalonia;
+using Avalonia.Styling;
+
+namespace DockReactiveUIManagedSample.Themes;
+
+public class FluentThemeManager : IThemeManager
+{
+ public void Switch(int index)
+ {
+ if (Application.Current is null)
+ {
+ return;
+ }
+
+ Application.Current.RequestedThemeVariant = index switch
+ {
+ 0 => ThemeVariant.Light,
+ 1 => ThemeVariant.Dark,
+ _ => Application.Current.RequestedThemeVariant
+ };
+ }
+}
diff --git a/samples/DockReactiveUIManagedSample/Themes/IThemeManager.cs b/samples/DockReactiveUIManagedSample/Themes/IThemeManager.cs
new file mode 100644
index 000000000..096a413ab
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/Themes/IThemeManager.cs
@@ -0,0 +1,6 @@
+namespace DockReactiveUIManagedSample.Themes;
+
+public interface IThemeManager
+{
+ void Switch(int index);
+}
diff --git a/samples/DockReactiveUIManagedSample/ViewLocator.cs b/samples/DockReactiveUIManagedSample/ViewLocator.cs
new file mode 100644
index 000000000..543bca3c2
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/ViewLocator.cs
@@ -0,0 +1,41 @@
+using System;
+using Avalonia.Controls;
+using Avalonia.Controls.Templates;
+//using CommunityToolkit.Mvvm.ComponentModel;
+using Dock.Model.Core;
+using ReactiveUI;
+using StaticViewLocator;
+
+namespace DockReactiveUIManagedSample;
+
+[StaticViewLocator]
+public partial class ViewLocator : IDataTemplate
+{
+ public Control? Build(object? data)
+ {
+ if (data is null)
+ {
+ return null;
+ }
+
+ var type = data.GetType();
+
+ if (s_views.TryGetValue(type, out var func))
+ {
+ return func.Invoke();
+ }
+
+ throw new Exception($"Unable to create view for type: {type}");
+ }
+
+ public bool Match(object? data)
+ {
+ if (data is null)
+ {
+ return false;
+ }
+
+ var type = data.GetType();
+ return data is IDockable || s_views.ContainsKey(type);
+ }
+}
diff --git a/samples/DockReactiveUIManagedSample/ViewModels/DockFactory.cs b/samples/DockReactiveUIManagedSample/ViewModels/DockFactory.cs
new file mode 100644
index 000000000..86a78ff43
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/ViewModels/DockFactory.cs
@@ -0,0 +1,202 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using DockReactiveUIManagedSample.Models.Documents;
+using DockReactiveUIManagedSample.Models.Tools;
+using DockReactiveUIManagedSample.ViewModels.Docks;
+using DockReactiveUIManagedSample.ViewModels.Documents;
+using DockReactiveUIManagedSample.ViewModels.Tools;
+using DockReactiveUIManagedSample.ViewModels.Views;
+using Dock.Avalonia.Controls;
+using Dock.Settings;
+using Dock.Model.Controls;
+using Dock.Model.Core;
+using Dock.Model.ReactiveUI;
+using Dock.Model.ReactiveUI.Controls;
+
+namespace DockReactiveUIManagedSample.ViewModels;
+
+[RequiresUnreferencedCode("Requires unreferenced code for CustomDocumentDock.")]
+[RequiresDynamicCode("Requires unreferenced code for CustomDocumentDock.")]
+public class DockFactory : Factory
+{
+ private readonly object _context;
+ private IRootDock? _rootDock;
+ private IDocumentDock? _documentDock;
+
+ public DockFactory(object context)
+ {
+ _context = context;
+ }
+
+ public override IDocumentDock CreateDocumentDock() => new CustomDocumentDock();
+
+ public override IRootDock CreateLayout()
+ {
+ var document1 = new DocumentViewModel {Id = "Document1", Title = "Document1"};
+ var document2 = new DocumentViewModel {Id = "Document2", Title = "Document2"};
+ var document3 = new DocumentViewModel {Id = "Document3", Title = "Document3", CanClose = true};
+ var tool1 = new Tool1ViewModel {Id = "Tool1", Title = "Tool1", KeepPinnedDockableVisible = true};
+ var tool2 = new Tool2ViewModel {Id = "Tool2", Title = "Tool2", KeepPinnedDockableVisible = true};
+ var tool3 = new Tool3ViewModel {Id = "Tool3", Title = "Tool3", CanDrag = false };
+ var tool4 = new Tool4ViewModel {Id = "Tool4", Title = "Tool4", CanDrag = false };
+ var tool5 = new Tool5ViewModel {Id = "Tool5", Title = "Tool5" };
+ var tool6 = new Tool6ViewModel {Id = "Tool6", Title = "Tool6", CanClose = true, CanPin = true};
+ var tool7 = new Tool7ViewModel {Id = "Tool7", Title = "Tool7", CanClose = false, CanPin = false};
+ var tool8 = new Tool8ViewModel {Id = "Tool8", Title = "Tool8", CanClose = false, CanPin = true};
+
+ var leftDock = new ProportionalDock
+ {
+ Proportion = 0.25,
+ Orientation = Orientation.Vertical,
+ ActiveDockable = null,
+ VisibleDockables = CreateList
+ (
+ new ToolDock
+ {
+ ActiveDockable = tool1,
+ VisibleDockables = CreateList(tool1, tool2),
+ Alignment = Alignment.Left,
+ // CanDrop = false
+ },
+ new ProportionalDockSplitter { CanResize = true },
+ new ToolDock
+ {
+ ActiveDockable = tool3,
+ VisibleDockables = CreateList(tool3, tool4),
+ Alignment = Alignment.Bottom,
+ CanDrag = false,
+ CanDrop = false
+ }
+ ),
+ // CanDrop = false
+ };
+
+ var rightDock = new ProportionalDock
+ {
+ Proportion = 0.25,
+ Orientation = Orientation.Vertical,
+ ActiveDockable = null,
+ VisibleDockables = CreateList
+ (
+ new ToolDock
+ {
+ ActiveDockable = tool5,
+ VisibleDockables = CreateList(tool5, tool6),
+ Alignment = Alignment.Top,
+ GripMode = GripMode.Hidden
+ },
+ new ProportionalDockSplitter(),
+ new ToolDock
+ {
+ ActiveDockable = tool7,
+ VisibleDockables = CreateList(tool7, tool8),
+ Alignment = Alignment.Right,
+ GripMode = GripMode.AutoHide
+ }
+ ),
+ // CanDrop = false
+ };
+
+ var documentDock = new CustomDocumentDock
+ {
+ IsCollapsable = false,
+ ActiveDockable = document1,
+ VisibleDockables = CreateList(document1, document2, document3),
+ CanCreateDocument = true,
+ // CanDrop = false,
+ EnableWindowDrag = true,
+ // CanCloseLastDockable = false,
+ };
+
+ var mainLayout = new ProportionalDock
+ {
+ Orientation = Orientation.Horizontal,
+ VisibleDockables = CreateList
+ (
+ leftDock,
+ new ProportionalDockSplitter(),
+ documentDock,
+ new ProportionalDockSplitter(),
+ rightDock
+ )
+ };
+
+ var dashboardView = new DashboardViewModel
+ {
+ Id = "Dashboard",
+ Title = "Dashboard"
+ };
+
+ var homeView = new HomeViewModel
+ {
+ Id = "Home",
+ Title = "Home",
+ ActiveDockable = mainLayout,
+ VisibleDockables = CreateList(mainLayout)
+ };
+
+ var rootDock = CreateRootDock();
+
+ rootDock.IsCollapsable = false;
+ rootDock.ActiveDockable = dashboardView;
+ rootDock.DefaultDockable = homeView;
+ rootDock.VisibleDockables = CreateList(dashboardView, homeView);
+
+ rootDock.LeftPinnedDockables = CreateList();
+ rootDock.RightPinnedDockables = CreateList();
+ rootDock.TopPinnedDockables = CreateList();
+ rootDock.BottomPinnedDockables = CreateList();
+
+ rootDock.PinnedDock = null;
+
+ _documentDock = documentDock;
+ _rootDock = rootDock;
+
+ return rootDock;
+ }
+
+ public override IDockWindow? CreateWindowFrom(IDockable dockable)
+ {
+ var window = base.CreateWindowFrom(dockable);
+
+ if (window != null)
+ {
+ window.Title = "Dock Avalonia Demo";
+ }
+ return window;
+ }
+
+ public override void InitLayout(IDockable layout)
+ {
+ ContextLocator = new Dictionary>
+ {
+ ["Document1"] = () => new DemoDocument(),
+ ["Document2"] = () => new DemoDocument(),
+ ["Document3"] = () => new DemoDocument(),
+ ["Tool1"] = () => new Tool1(),
+ ["Tool2"] = () => new Tool2(),
+ ["Tool3"] = () => new Tool3(),
+ ["Tool4"] = () => new Tool4(),
+ ["Tool5"] = () => new Tool5(),
+ ["Tool6"] = () => new Tool6(),
+ ["Tool7"] = () => new Tool7(),
+ ["Tool8"] = () => new Tool8(),
+ ["Dashboard"] = () => layout,
+ ["Home"] = () => _context
+ };
+
+ DockableLocator = new Dictionary>()
+ {
+ ["Root"] = () => _rootDock,
+ ["Documents"] = () => _documentDock
+ };
+
+ HostWindowLocator = new Dictionary>
+ {
+ [nameof(IDockWindow)] = () => DockSettings.UseManagedWindows ? new ManagedHostWindow() : new HostWindow()
+ };
+
+ base.InitLayout(layout);
+ }
+}
diff --git a/samples/DockReactiveUIManagedSample/ViewModels/Docks/CustomDocumentDock.cs b/samples/DockReactiveUIManagedSample/ViewModels/Docks/CustomDocumentDock.cs
new file mode 100644
index 000000000..c529738cc
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/ViewModels/Docks/CustomDocumentDock.cs
@@ -0,0 +1,31 @@
+using System.Diagnostics.CodeAnalysis;
+using DockReactiveUIManagedSample.ViewModels.Documents;
+using Dock.Model.ReactiveUI.Controls;
+using ReactiveUI;
+
+namespace DockReactiveUIManagedSample.ViewModels.Docks;
+
+[RequiresUnreferencedCode("Requires unreferenced code for ReactiveCommand.Create.")]
+[RequiresDynamicCode("Requires unreferenced code for ReactiveCommand.Create.")]
+public class CustomDocumentDock : DocumentDock
+{
+ public CustomDocumentDock()
+ {
+ CreateDocument = ReactiveCommand.Create(CreateNewDocument);
+ }
+
+ private void CreateNewDocument()
+ {
+ if (!CanCreateDocument)
+ {
+ return;
+ }
+
+ var index = VisibleDockables?.Count + 1;
+ var document = new DocumentViewModel {Id = $"Document{index}", Title = $"Document{index}"};
+
+ Factory?.AddDockable(this, document);
+ Factory?.SetActiveDockable(document);
+ Factory?.SetFocusedDockable(this, document);
+ }
+}
diff --git a/samples/DockReactiveUIManagedSample/ViewModels/Documents/DocumentViewModel.cs b/samples/DockReactiveUIManagedSample/ViewModels/Documents/DocumentViewModel.cs
new file mode 100644
index 000000000..3b74b4afc
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/ViewModels/Documents/DocumentViewModel.cs
@@ -0,0 +1,7 @@
+using Dock.Model.ReactiveUI.Controls;
+
+namespace DockReactiveUIManagedSample.ViewModels.Documents;
+
+public class DocumentViewModel : Document
+{
+}
diff --git a/samples/DockReactiveUIManagedSample/ViewModels/MainWindowViewModel.cs b/samples/DockReactiveUIManagedSample/ViewModels/MainWindowViewModel.cs
new file mode 100644
index 000000000..cd9c74987
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/ViewModels/MainWindowViewModel.cs
@@ -0,0 +1,197 @@
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Windows.Input;
+using DockReactiveUIManagedSample.Models;
+using Dock.Model.Controls;
+using Dock.Model.Core;
+using ReactiveUI;
+
+namespace DockReactiveUIManagedSample.ViewModels;
+
+[RequiresUnreferencedCode("Requires unreferenced code for RaiseAndSetIfChanged.")]
+[RequiresDynamicCode("Requires unreferenced code for RaiseAndSetIfChanged.")]
+public class MainWindowViewModel : ReactiveObject
+{
+ private readonly IFactory? _factory;
+ private IRootDock? _layout;
+
+ public IRootDock? Layout
+ {
+ get => _layout;
+ set => this.RaiseAndSetIfChanged(ref _layout, value);
+ }
+
+ public ICommand NewLayout { get; }
+
+ public MainWindowViewModel()
+ {
+ _factory = new DockFactory(new DemoData());
+
+ DebugFactoryEvents(_factory);
+
+ var layout = _factory?.CreateLayout();
+ if (layout is not null)
+ {
+ _factory?.InitLayout(layout);
+ layout.Navigate.Execute("Home");
+ }
+ Layout = layout;
+
+ NewLayout = ReactiveCommand.Create(ResetLayout);
+ }
+
+ private void DebugFactoryEvents(IFactory factory)
+ {
+ factory.ActiveDockableChanged += (_, args) =>
+ {
+ Debug.WriteLine($"[ActiveDockableChanged] Title='{args.Dockable?.Title}'");
+ };
+
+ factory.FocusedDockableChanged += (_, args) =>
+ {
+ Debug.WriteLine($"[FocusedDockableChanged] Title='{args.Dockable?.Title}'");
+ };
+
+ factory.DockableAdded += (_, args) =>
+ {
+ Debug.WriteLine($"[DockableAdded] Title='{args.Dockable?.Title}'");
+ };
+
+ factory.DockableRemoved += (_, args) =>
+ {
+ Debug.WriteLine($"[DockableRemoved] Title='{args.Dockable?.Title}'");
+ };
+
+ factory.DockableClosed += (_, args) =>
+ {
+ Debug.WriteLine($"[DockableClosed] Title='{args.Dockable?.Title}'");
+ };
+
+ factory.DockableMoved += (_, args) =>
+ {
+ Debug.WriteLine($"[DockableMoved] Title='{args.Dockable?.Title}'");
+ };
+
+ factory.DockableDocked += (_, args) =>
+ {
+ Debug.WriteLine($"[DockableDocked] Title='{args.Dockable?.Title}', Operation='{args.Operation}'");
+ };
+
+ factory.DockableUndocked += (_, args) =>
+ {
+ Debug.WriteLine($"[DockableUndocked] Title='{args.Dockable?.Title}', Operation='{args.Operation}'");
+ };
+
+ factory.DockableSwapped += (_, args) =>
+ {
+ Debug.WriteLine($"[DockableSwapped] Title='{args.Dockable?.Title}'");
+ };
+
+ factory.DockablePinned += (_, args) =>
+ {
+ Debug.WriteLine($"[DockablePinned] Title='{args.Dockable?.Title}'");
+ };
+
+ factory.DockableUnpinned += (_, args) =>
+ {
+ Debug.WriteLine($"[DockableUnpinned] Title='{args.Dockable?.Title}'");
+ };
+
+ factory.WindowOpened += (_, args) =>
+ {
+ Debug.WriteLine($"[WindowOpened] Title='{args.Window?.Title}'");
+ };
+
+ factory.WindowClosed += (_, args) =>
+ {
+ Debug.WriteLine($"[WindowClosed] Title='{args.Window?.Title}'");
+ };
+
+ factory.WindowClosing += (_, args) =>
+ {
+ // NOTE: Set to True to cancel window closing.
+#if false
+ args.Cancel = true;
+#endif
+ Debug.WriteLine($"[WindowClosing] Title='{args.Window?.Title}', Cancel={args.Cancel}");
+ };
+
+ factory.WindowAdded += (_, args) =>
+ {
+ Debug.WriteLine($"[WindowAdded] Title='{args.Window?.Title}'");
+ };
+
+ factory.WindowRemoved += (_, args) =>
+ {
+ Debug.WriteLine($"[WindowRemoved] Title='{args.Window?.Title}'");
+ };
+
+ factory.WindowMoveDragBegin += (_, args) =>
+ {
+ // NOTE: Set to True to cancel window dragging.
+#if false
+ args.Cancel = true;
+#endif
+ Debug.WriteLine($"[WindowMoveDragBegin] Title='{args.Window?.Title}', Cancel={args.Cancel}, X='{args.Window?.X}', Y='{args.Window?.Y}'");
+ };
+
+ factory.WindowMoveDrag += (_, args) =>
+ {
+ Debug.WriteLine($"[WindowMoveDrag] Title='{args.Window?.Title}', X='{args.Window?.X}', Y='{args.Window?.Y}");
+ };
+
+ factory.WindowMoveDragEnd += (_, args) =>
+ {
+ Debug.WriteLine($"[WindowMoveDragEnd] Title='{args.Window?.Title}', X='{args.Window?.X}', Y='{args.Window?.Y}");
+ };
+
+ factory.WindowActivated += (_, args) =>
+ {
+ Debug.WriteLine($"[WindowActivated] Title='{args.Window?.Title}'");
+ };
+
+ factory.DockableActivated += (_, args) =>
+ {
+ Debug.WriteLine($"[DockableActivated] Title='{args.Dockable?.Title}'");
+ };
+
+ factory.WindowDeactivated += (_, args) =>
+ {
+ Debug.WriteLine($"[WindowDeactivated] Title='{args.Window?.Title}'");
+ };
+
+ factory.DockableDeactivated += (_, args) =>
+ {
+ Debug.WriteLine($"[DockableDeactivated] Title='{args.Dockable?.Title}'");
+ };
+ }
+
+ public void CloseLayout()
+ {
+ if (Layout is IDock dock)
+ {
+ if (dock.Close.CanExecute(null))
+ {
+ dock.Close.Execute(null);
+ }
+ }
+ }
+
+ public void ResetLayout()
+ {
+ if (Layout is not null)
+ {
+ if (Layout.Close.CanExecute(null))
+ {
+ Layout.Close.Execute(null);
+ }
+ }
+
+ var layout = _factory?.CreateLayout();
+ if (layout is not null)
+ {
+ _factory?.InitLayout(layout);
+ Layout = layout;
+ }
+ }
+}
diff --git a/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool1ViewModel.cs b/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool1ViewModel.cs
new file mode 100644
index 000000000..b86b1c2d6
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool1ViewModel.cs
@@ -0,0 +1,7 @@
+using Dock.Model.ReactiveUI.Controls;
+
+namespace DockReactiveUIManagedSample.ViewModels.Tools;
+
+public class Tool1ViewModel : Tool
+{
+}
diff --git a/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool2ViewModel.cs b/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool2ViewModel.cs
new file mode 100644
index 000000000..9a39a8a86
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool2ViewModel.cs
@@ -0,0 +1,7 @@
+using Dock.Model.ReactiveUI.Controls;
+
+namespace DockReactiveUIManagedSample.ViewModels.Tools;
+
+public class Tool2ViewModel : Tool
+{
+}
diff --git a/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool3ViewModel.cs b/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool3ViewModel.cs
new file mode 100644
index 000000000..759a7e557
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool3ViewModel.cs
@@ -0,0 +1,7 @@
+using Dock.Model.ReactiveUI.Controls;
+
+namespace DockReactiveUIManagedSample.ViewModels.Tools;
+
+public class Tool3ViewModel : Tool
+{
+}
diff --git a/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool4ViewModel.cs b/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool4ViewModel.cs
new file mode 100644
index 000000000..5a1ba4152
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool4ViewModel.cs
@@ -0,0 +1,7 @@
+using Dock.Model.ReactiveUI.Controls;
+
+namespace DockReactiveUIManagedSample.ViewModels.Tools;
+
+public class Tool4ViewModel : Tool
+{
+}
diff --git a/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool5ViewModel.cs b/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool5ViewModel.cs
new file mode 100644
index 000000000..1d5c7d394
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool5ViewModel.cs
@@ -0,0 +1,7 @@
+using Dock.Model.ReactiveUI.Controls;
+
+namespace DockReactiveUIManagedSample.ViewModels.Tools;
+
+public class Tool5ViewModel : Tool
+{
+}
diff --git a/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool6ViewModel.cs b/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool6ViewModel.cs
new file mode 100644
index 000000000..dead083a5
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool6ViewModel.cs
@@ -0,0 +1,7 @@
+using Dock.Model.ReactiveUI.Controls;
+
+namespace DockReactiveUIManagedSample.ViewModels.Tools;
+
+public class Tool6ViewModel : Tool
+{
+}
diff --git a/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool7ViewModel.cs b/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool7ViewModel.cs
new file mode 100644
index 000000000..e57d75680
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool7ViewModel.cs
@@ -0,0 +1,7 @@
+using Dock.Model.ReactiveUI.Controls;
+
+namespace DockReactiveUIManagedSample.ViewModels.Tools;
+
+public class Tool7ViewModel : Tool
+{
+}
diff --git a/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool8ViewModel.cs b/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool8ViewModel.cs
new file mode 100644
index 000000000..af4765c90
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/ViewModels/Tools/Tool8ViewModel.cs
@@ -0,0 +1,7 @@
+using Dock.Model.ReactiveUI.Controls;
+
+namespace DockReactiveUIManagedSample.ViewModels.Tools;
+
+public class Tool8ViewModel : Tool
+{
+}
diff --git a/samples/DockReactiveUIManagedSample/ViewModels/Views/DashboardViewModel.cs b/samples/DockReactiveUIManagedSample/ViewModels/Views/DashboardViewModel.cs
new file mode 100644
index 000000000..6fb209f1f
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/ViewModels/Views/DashboardViewModel.cs
@@ -0,0 +1,7 @@
+using Dock.Model.ReactiveUI.Core;
+
+namespace DockReactiveUIManagedSample.ViewModels.Views;
+
+public class DashboardViewModel : DockBase
+{
+}
diff --git a/samples/DockReactiveUIManagedSample/ViewModels/Views/HomeViewModel.cs b/samples/DockReactiveUIManagedSample/ViewModels/Views/HomeViewModel.cs
new file mode 100644
index 000000000..be4263db6
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/ViewModels/Views/HomeViewModel.cs
@@ -0,0 +1,7 @@
+using Dock.Model.ReactiveUI.Controls;
+
+namespace DockReactiveUIManagedSample.ViewModels.Views;
+
+public class HomeViewModel : RootDock
+{
+}
diff --git a/samples/DockReactiveUIManagedSample/Views/DockableOptionsView.axaml b/samples/DockReactiveUIManagedSample/Views/DockableOptionsView.axaml
new file mode 100644
index 000000000..d8ebf6812
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/Views/DockableOptionsView.axaml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/DockReactiveUIManagedSample/Views/DockableOptionsView.axaml.cs b/samples/DockReactiveUIManagedSample/Views/DockableOptionsView.axaml.cs
new file mode 100644
index 000000000..28b6508d0
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/Views/DockableOptionsView.axaml.cs
@@ -0,0 +1,17 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace DockReactiveUIManagedSample.Views;
+
+public partial class DockableOptionsView : UserControl
+{
+ public DockableOptionsView()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+}
diff --git a/samples/DockReactiveUIManagedSample/Views/Documents/DocumentView.axaml b/samples/DockReactiveUIManagedSample/Views/Documents/DocumentView.axaml
new file mode 100644
index 000000000..41ede0d87
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/Views/Documents/DocumentView.axaml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/DockReactiveUIManagedSample/Views/Documents/DocumentView.axaml.cs b/samples/DockReactiveUIManagedSample/Views/Documents/DocumentView.axaml.cs
new file mode 100644
index 000000000..ee5fe4153
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/Views/Documents/DocumentView.axaml.cs
@@ -0,0 +1,17 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace DockReactiveUIManagedSample.Views.Documents;
+
+public partial class DocumentView : UserControl
+{
+ public DocumentView()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+}
diff --git a/samples/DockReactiveUIManagedSample/Views/MainView.axaml b/samples/DockReactiveUIManagedSample/Views/MainView.axaml
new file mode 100644
index 000000000..1e0718b58
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/Views/MainView.axaml
@@ -0,0 +1,75 @@
+
+
+
+
+
+ M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10Zm0-2V4a8 8 0 1 1 0 16Z
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/DockReactiveUIManagedSample/Views/MainView.axaml.cs b/samples/DockReactiveUIManagedSample/Views/MainView.axaml.cs
new file mode 100644
index 000000000..3ba6010f1
--- /dev/null
+++ b/samples/DockReactiveUIManagedSample/Views/MainView.axaml.cs
@@ -0,0 +1,35 @@
+using System.Diagnostics.CodeAnalysis;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace DockReactiveUIManagedSample.Views;
+
+[RequiresUnreferencedCode("Requires unreferenced code for ThemeManager.")]
+[RequiresDynamicCode("Requires unreferenced code for ThemeManager.")]
+public partial class MainView : UserControl
+{
+ public MainView()
+ {
+ InitializeComponent();
+ InitializeThemes();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ private void InitializeThemes()
+ {
+ var dark = false;
+ var theme = this.Find