diff --git a/docfx/articles/dock-dockable-properties.md b/docfx/articles/dock-dockable-properties.md index 80e1e3805..fa336a0f2 100644 --- a/docfx/articles/dock-dockable-properties.md +++ b/docfx/articles/dock-dockable-properties.md @@ -32,6 +32,7 @@ Dockable items such as documents, tools and docks implement the `IDockable` inte | `CanFloat` | Controls if the item may be detached into a floating window. | | `CanDrag` | Enables dragging the dockable to another position. | | `CanDrop` | Determines if other dockables can be dropped onto this one. | +| `CanDockAsDocument` | Controls whether the dockable can be docked as a tabbed document. | | `IsModified` | Marks a dockable as having unsaved changes. | | `DockGroup` | Group identifier that restricts which dockables can dock together. See [Docking Groups](dock-docking-groups.md). | diff --git a/docfx/articles/dock-faq.md b/docfx/articles/dock-faq.md index 97db9d9e6..d8255cb96 100644 --- a/docfx/articles/dock-faq.md +++ b/docfx/articles/dock-faq.md @@ -225,6 +225,13 @@ you. Dockables may still be floated programmatically unless their `CanFloat` property is set to `false`. +To prevent a dockable from being docked into document docks (including the +"Dock as Tabbed Document" command), set `CanDockAsDocument` to `false`: + +```csharp +tool.CanDockAsDocument = false; +``` + **How can I prevent certain dockables from docking together?** Use docking groups to control which dockables can dock together. Set the `DockGroup` property on your dockables: diff --git a/src/Dock.Avalonia.Diagnostics/Controls/DockableDebugView.axaml b/src/Dock.Avalonia.Diagnostics/Controls/DockableDebugView.axaml index 209fd130c..12617241a 100644 --- a/src/Dock.Avalonia.Diagnostics/Controls/DockableDebugView.axaml +++ b/src/Dock.Avalonia.Diagnostics/Controls/DockableDebugView.axaml @@ -4,7 +4,7 @@ x:Class="Dock.Avalonia.Diagnostics.Controls.DockableDebugView" x:DataType="core:IDockable" x:CompileBindings="True"> - @@ -58,7 +58,9 @@ - - + + + + diff --git a/src/Dock.Avalonia.Themes.Fluent/Controls/ToolChromeControl.axaml b/src/Dock.Avalonia.Themes.Fluent/Controls/ToolChromeControl.axaml index c42a8dd4f..36d7d8945 100644 --- a/src/Dock.Avalonia.Themes.Fluent/Controls/ToolChromeControl.axaml +++ b/src/Dock.Avalonia.Themes.Fluent/Controls/ToolChromeControl.axaml @@ -30,8 +30,14 @@ IsVisible="{Binding ActiveDockable.CanPin, FallbackValue=False}"/> + CommandParameter="{Binding ActiveDockable}"> + + + + + + + + CommandParameter="{Binding}"> + + + + + + + diff --git a/src/Dock.Avalonia.Themes.Fluent/Controls/ToolTabStripItem.axaml b/src/Dock.Avalonia.Themes.Fluent/Controls/ToolTabStripItem.axaml index 63b15ac54..66b9c49c0 100644 --- a/src/Dock.Avalonia.Themes.Fluent/Controls/ToolTabStripItem.axaml +++ b/src/Dock.Avalonia.Themes.Fluent/Controls/ToolTabStripItem.axaml @@ -51,8 +51,14 @@ IsVisible="{Binding CanPin, FallbackValue=False}" /> + CommandParameter="{Binding}"> + + + + + + + CanDropProperty = AvaloniaProperty.RegisterDirect(nameof(CanDrop), o => o.CanDrop, (o, v) => o.CanDrop = v); + /// + /// Defines the property. + /// + public static readonly DirectProperty CanDockAsDocumentProperty = + AvaloniaProperty.RegisterDirect(nameof(CanDockAsDocument), o => o.CanDockAsDocument, (o, v) => o.CanDockAsDocument = v); + /// /// Defines the property. /// @@ -228,6 +234,7 @@ public abstract class DockableBase : ReactiveBase, IDockable, IDockSelectorInfo private bool _canFloat = true; private bool _canDrag = true; private bool _canDrop = true; + private bool _canDockAsDocument = true; private double _minWidth = double.NaN; private double _maxWidth = double.NaN; private double _minHeight = double.NaN; @@ -481,6 +488,15 @@ public bool CanDrop set => SetAndRaise(CanDropProperty, ref _canDrop, value); } + /// + [DataMember(IsRequired = false, EmitDefaultValue = true)] + [JsonPropertyName("CanDockAsDocument")] + public bool CanDockAsDocument + { + get => _canDockAsDocument; + set => SetAndRaise(CanDockAsDocumentProperty, ref _canDockAsDocument, value); + } + /// [DataMember(IsRequired = false, EmitDefaultValue = true)] [JsonPropertyName("IsModified")] diff --git a/src/Dock.Model.Avalonia/Json/AvaloniaDockSerializer.cs b/src/Dock.Model.Avalonia/Json/AvaloniaDockSerializer.cs index aab0e238c..bfdb11649 100644 --- a/src/Dock.Model.Avalonia/Json/AvaloniaDockSerializer.cs +++ b/src/Dock.Model.Avalonia/Json/AvaloniaDockSerializer.cs @@ -63,6 +63,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", }, [typeof(IDocument)] = new List { @@ -78,6 +79,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", }, [typeof(IDocumentContent)] = new List { @@ -93,6 +95,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", }, [typeof(ITool)] = new List { @@ -108,6 +111,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", }, [typeof(IToolContent)] = new List { @@ -123,6 +127,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", }, [typeof(IDock)] = new List { @@ -138,6 +143,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", // IDock "VisibleDockables", "ActiveDockable", @@ -164,6 +170,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", // IDock "VisibleDockables", "ActiveDockable", @@ -192,6 +199,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", // IDock "VisibleDockables", "ActiveDockable", @@ -220,6 +228,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", // IDock "VisibleDockables", "ActiveDockable", @@ -246,6 +255,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", // IDock "VisibleDockables", "ActiveDockable", @@ -274,6 +284,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", // IDock "VisibleDockables", "ActiveDockable", @@ -300,6 +311,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", // IDock "VisibleDockables", "ActiveDockable", @@ -335,6 +347,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", // IDock "VisibleDockables", "ActiveDockable", @@ -366,6 +379,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", }, [typeof(DockBase)] = new List { @@ -381,6 +395,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", // IDock "VisibleDockables", "ActiveDockable", @@ -407,6 +422,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", }, [typeof(Tool)] = new List { @@ -422,6 +438,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", }, [typeof(DockDock)] = new List { @@ -437,6 +454,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", // IDock "VisibleDockables", "ActiveDockable", @@ -465,6 +483,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", // IDock "VisibleDockables", "ActiveDockable", @@ -493,6 +512,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", // IDock "VisibleDockables", "ActiveDockable", @@ -521,6 +541,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", // IDock "VisibleDockables", "ActiveDockable", @@ -546,6 +567,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", // IDock "VisibleDockables", "ActiveDockable", @@ -581,6 +603,7 @@ public AvaloniaDockSerializer() "CanFloat", "CanDrag", "CanDrop", + "CanDockAsDocument", // IDock "VisibleDockables", "ActiveDockable", diff --git a/src/Dock.Model.CaliburMicro/Core/DockableBase.cs b/src/Dock.Model.CaliburMicro/Core/DockableBase.cs index 34304e9e2..036ce8410 100644 --- a/src/Dock.Model.CaliburMicro/Core/DockableBase.cs +++ b/src/Dock.Model.CaliburMicro/Core/DockableBase.cs @@ -38,6 +38,7 @@ public abstract class DockableBase : CaliburMicroBase, IDockable, IDockSelectorI private bool _canFloat = true; private bool _canDrag = true; private bool _canDrop = true; + private bool _canDockAsDocument = true; private bool _isModified; private string? _dockGroup; private bool _showInSelector = true; @@ -259,6 +260,14 @@ public bool CanDrop set => Set(ref _canDrop, value); } + /// + [DataMember(IsRequired = false, EmitDefaultValue = true)] + public bool CanDockAsDocument + { + get => _canDockAsDocument; + set => Set(ref _canDockAsDocument, value); + } + /// [DataMember(IsRequired = false, EmitDefaultValue = true)] public bool IsModified diff --git a/src/Dock.Model.Inpc/Core/DockableBase.cs b/src/Dock.Model.Inpc/Core/DockableBase.cs index 0fd603275..19f505bf5 100644 --- a/src/Dock.Model.Inpc/Core/DockableBase.cs +++ b/src/Dock.Model.Inpc/Core/DockableBase.cs @@ -35,6 +35,7 @@ public abstract class DockableBase : ReactiveBase, IDockable, IDockSelectorInfo private bool _canFloat = true; private bool _canDrag = true; private bool _canDrop = true; + private bool _canDockAsDocument = true; private double _minWidth = double.NaN; private double _maxWidth = double.NaN; private double _minHeight = double.NaN; @@ -260,6 +261,14 @@ public bool CanDrop set => SetProperty(ref _canDrop, value); } + /// + [DataMember(IsRequired = false, EmitDefaultValue = true)] + public bool CanDockAsDocument + { + get => _canDockAsDocument; + set => SetProperty(ref _canDockAsDocument, value); + } + /// [DataMember(IsRequired = false, EmitDefaultValue = true)] public bool IsModified diff --git a/src/Dock.Model.Mvvm/Core/DockableBase.cs b/src/Dock.Model.Mvvm/Core/DockableBase.cs index b865b71b2..b41d18b5e 100644 --- a/src/Dock.Model.Mvvm/Core/DockableBase.cs +++ b/src/Dock.Model.Mvvm/Core/DockableBase.cs @@ -34,6 +34,7 @@ public abstract class DockableBase : ReactiveBase, IDockable, IDockSelectorInfo private bool _canFloat = true; private bool _canDrag = true; private bool _canDrop = true; + private bool _canDockAsDocument = true; private double _minWidth = double.NaN; private double _maxWidth = double.NaN; private double _minHeight = double.NaN; @@ -260,6 +261,14 @@ public bool CanDrop set => SetProperty(ref _canDrop, value); } + /// + [DataMember(IsRequired = false, EmitDefaultValue = true)] + public bool CanDockAsDocument + { + get => _canDockAsDocument; + set => SetProperty(ref _canDockAsDocument, value); + } + /// [DataMember(IsRequired = false, EmitDefaultValue = true)] public bool IsModified diff --git a/src/Dock.Model.Prism/Core/DockableBase.cs b/src/Dock.Model.Prism/Core/DockableBase.cs index 86a761c55..8deeafa69 100644 --- a/src/Dock.Model.Prism/Core/DockableBase.cs +++ b/src/Dock.Model.Prism/Core/DockableBase.cs @@ -34,6 +34,7 @@ public abstract class DockableBase : ReactiveBase, IDockable, IDockSelectorInfo private bool _canFloat = true; private bool _canDrag = true; private bool _canDrop = true; + private bool _canDockAsDocument = true; private double _minWidth = double.NaN; private double _maxWidth = double.NaN; private double _minHeight = double.NaN; @@ -260,6 +261,14 @@ public bool CanDrop set => SetProperty(ref _canDrop, value); } + /// + [DataMember(IsRequired = false, EmitDefaultValue = true)] + public bool CanDockAsDocument + { + get => _canDockAsDocument; + set => SetProperty(ref _canDockAsDocument, value); + } + /// [DataMember(IsRequired = false, EmitDefaultValue = true)] public bool IsModified diff --git a/src/Dock.Model.ReactiveProperty/Core/DockableBase.cs b/src/Dock.Model.ReactiveProperty/Core/DockableBase.cs index 72c86e02c..193919355 100644 --- a/src/Dock.Model.ReactiveProperty/Core/DockableBase.cs +++ b/src/Dock.Model.ReactiveProperty/Core/DockableBase.cs @@ -35,6 +35,7 @@ public abstract class DockableBase : ReactiveBase, IDockable, IDockSelectorInfo private bool _canFloat = true; private bool _canDrag = true; private bool _canDrop = true; + private bool _canDockAsDocument = true; private double _minWidth = double.NaN; private double _maxWidth = double.NaN; private double _minHeight = double.NaN; @@ -260,6 +261,14 @@ public bool CanDrop set => SetProperty(ref _canDrop, value); } + /// + [DataMember(IsRequired = false, EmitDefaultValue = true)] + public bool CanDockAsDocument + { + get => _canDockAsDocument; + set => SetProperty(ref _canDockAsDocument, value); + } + /// [DataMember(IsRequired = false, EmitDefaultValue = true)] public bool IsModified diff --git a/src/Dock.Model.ReactiveUI/Core/DockableBase.cs b/src/Dock.Model.ReactiveUI/Core/DockableBase.cs index 3334021d4..118388d71 100644 --- a/src/Dock.Model.ReactiveUI/Core/DockableBase.cs +++ b/src/Dock.Model.ReactiveUI/Core/DockableBase.cs @@ -35,6 +35,7 @@ protected DockableBase() _canFloat = true; _canDrag = true; _canDrop = true; + _canDockAsDocument = true; _minWidth = double.NaN; _maxWidth = double.NaN; _minHeight = double.NaN; @@ -176,6 +177,11 @@ protected DockableBase() [Reactive] public partial bool CanDrop { get; set; } + /// + [DataMember(IsRequired = false, EmitDefaultValue = true)] + [Reactive] + public partial bool CanDockAsDocument { get; set; } + /// [DataMember(IsRequired = false, EmitDefaultValue = true)] [Reactive] diff --git a/src/Dock.Model/Core/IDockable.cs b/src/Dock.Model/Core/IDockable.cs index d59921849..6b2df89d2 100644 --- a/src/Dock.Model/Core/IDockable.cs +++ b/src/Dock.Model/Core/IDockable.cs @@ -140,6 +140,11 @@ public interface IDockable : IControlRecyclingIdProvider /// bool CanDrop { get; set; } + /// + /// Gets or sets if the dockable can be docked as a document. + /// + bool CanDockAsDocument { get; set; } + /// /// Gets or sets whether the dockable has unsaved changes. /// diff --git a/src/Dock.Model/DockManager.cs b/src/Dock.Model/DockManager.cs index 8d7f26570..6c23bd1b4 100644 --- a/src/Dock.Model/DockManager.cs +++ b/src/Dock.Model/DockManager.cs @@ -56,6 +56,16 @@ private static bool HasSizeConflict(ITool a, ITool b) return widthConflict || heightConflict; } + private static bool AllowsDocumentDocking(IDockable sourceDockable, IDockable targetDockable) + { + if (sourceDockable.CanDockAsDocument) + { + return true; + } + + return targetDockable is not IDocumentDock && targetDockable is not IDocument; + } + private bool DockDockable(IDockable sourceDockable, IDock sourceDockableOwner, IDock targetDock, DockOperation operation, bool bExecute) @@ -225,6 +235,11 @@ public bool ValidateTool(ITool sourceTool, IDockable targetDockable, DragAction return false; } + if (!AllowsDocumentDocking(sourceTool, targetDockable)) + { + return false; + } + return targetDockable switch { IRootDock rootDock => DockDockableIntoRoot(sourceTool, rootDock, action, operation, bExecute), @@ -399,6 +414,11 @@ public bool ValidateDocument(IDocument sourceDocument, IDockable targetDockable, return false; } + if (!AllowsDocumentDocking(sourceDocument, targetDockable)) + { + return false; + } + if (targetDockable is ITool or IToolDock) { return false; @@ -422,6 +442,11 @@ public bool ValidateDock(IDock sourceDock, IDockable targetDockable, DragAction return false; } + if (!AllowsDocumentDocking(sourceDock, targetDockable)) + { + return false; + } + return targetDockable switch { IRootDock _ => _dockService.DockDockableIntoWindow(sourceDock, targetDockable, ScreenPosition, bExecute), diff --git a/src/Dock.Model/FactoryBase.Dockable.cs b/src/Dock.Model/FactoryBase.Dockable.cs index e4fc27f52..154d990b4 100644 --- a/src/Dock.Model/FactoryBase.Dockable.cs +++ b/src/Dock.Model/FactoryBase.Dockable.cs @@ -1065,6 +1065,11 @@ public virtual void FloatAllDockables(IDockable dockable) /// public virtual void DockAsDocument(IDockable dockable) { + if (!dockable.CanDockAsDocument) + { + return; + } + if (dockable.Owner is not IDock sourceDock) { return; diff --git a/src/Dock.Model/FluentExtensions.cs b/src/Dock.Model/FluentExtensions.cs index 824540037..1dcc1d9ca 100644 --- a/src/Dock.Model/FluentExtensions.cs +++ b/src/Dock.Model/FluentExtensions.cs @@ -593,6 +593,14 @@ private static IList EnsureList(IList? list) /// The same instance for chaining. public static T WithCanDrop(this T dockable, bool value) where T : IDockable { dockable.CanDrop = value; return dockable; } /// + /// Sets the flag. + /// + /// Dockable type. + /// The instance to configure. + /// Whether it can be docked as a document. + /// The same instance for chaining. + public static T WithCanDockAsDocument(this T dockable, bool value) where T : IDockable { dockable.CanDockAsDocument = value; return dockable; } + /// /// Sets the flag. /// /// Dockable type. diff --git a/tests/Dock.Avalonia.HeadlessTests/DockManagerDocumentTests.cs b/tests/Dock.Avalonia.HeadlessTests/DockManagerDocumentTests.cs index d4615e91c..f1414c140 100644 --- a/tests/Dock.Avalonia.HeadlessTests/DockManagerDocumentTests.cs +++ b/tests/Dock.Avalonia.HeadlessTests/DockManagerDocumentTests.cs @@ -33,6 +33,20 @@ public void ValidateDocument_ReturnsFalse_When_TargetCannotDrop() Assert.False(result); } + [AvaloniaFact] + public void ValidateDocument_ReturnsFalse_When_SourceCannotDockAsDocument_And_TargetIsDocumentDock() + { + var manager = new DockManager(new DockService()); + var sourceDock = new DocumentDock { VisibleDockables = new AvaloniaList() }; + var source = new Document { Owner = sourceDock, CanDockAsDocument = false }; + sourceDock.VisibleDockables!.Add(source); + var target = new DocumentDock { VisibleDockables = new AvaloniaList(), CanDrop = true }; + + var result = manager.ValidateDocument(source, target, DragAction.Move, DockOperation.Fill, false); + + Assert.False(result); + } + [AvaloniaFact] public void IsDockTargetVisible_ReturnsFalse_For_Same_Dockable() { diff --git a/tests/Dock.Avalonia.HeadlessTests/DockManagerTests.cs b/tests/Dock.Avalonia.HeadlessTests/DockManagerTests.cs index 2176a89f6..1ed011e6f 100644 --- a/tests/Dock.Avalonia.HeadlessTests/DockManagerTests.cs +++ b/tests/Dock.Avalonia.HeadlessTests/DockManagerTests.cs @@ -54,4 +54,32 @@ public void ValidateTool_ReturnsTrue_When_Valid() var result = manager.ValidateTool(tool, targetDock, DragAction.Move, DockOperation.Fill, false); Assert.True(result); } + + [AvaloniaFact] + public void ValidateTool_ReturnsFalse_When_SourceCannotDockAsDocument_And_TargetIsDocumentDock() + { + var manager = new DockManager(new DockService()); + var sourceDock = new ToolDock { VisibleDockables = new AvaloniaList() }; + var tool = new Tool { Owner = sourceDock, CanDockAsDocument = false }; + sourceDock.VisibleDockables!.Add(tool); + var targetDock = new DocumentDock { VisibleDockables = new AvaloniaList(), CanDrop = true }; + + var result = manager.ValidateTool(tool, targetDock, DragAction.Move, DockOperation.Fill, false); + + Assert.False(result); + } + + [AvaloniaFact] + public void ValidateTool_ReturnsTrue_When_SourceCanDockAsDocument_And_TargetIsDocumentDock() + { + var manager = new DockManager(new DockService()); + var sourceDock = new ToolDock { VisibleDockables = new AvaloniaList() }; + var tool = new Tool { Owner = sourceDock, CanDockAsDocument = true }; + sourceDock.VisibleDockables!.Add(tool); + var targetDock = new DocumentDock { VisibleDockables = new AvaloniaList(), CanDrop = true }; + + var result = manager.ValidateTool(tool, targetDock, DragAction.Move, DockOperation.Fill, false); + + Assert.True(result); + } } diff --git a/tests/Dock.Avalonia.HeadlessTests/FactoryDockAsDocumentTests.cs b/tests/Dock.Avalonia.HeadlessTests/FactoryDockAsDocumentTests.cs new file mode 100644 index 000000000..f8b901418 --- /dev/null +++ b/tests/Dock.Avalonia.HeadlessTests/FactoryDockAsDocumentTests.cs @@ -0,0 +1,32 @@ +using Avalonia.Headless.XUnit; +using Dock.Model.Avalonia; +using Dock.Model.Avalonia.Controls; +using Dock.Model.Core; +using Xunit; + +namespace Dock.Avalonia.HeadlessTests; + +public class FactoryDockAsDocumentTests +{ + [AvaloniaFact] + public void DockAsDocument_DoesNothing_When_DockableCannotDockAsDocument() + { + var factory = new Factory(); + var root = new RootDock { VisibleDockables = factory.CreateList() }; + root.Factory = factory; + + var documentDock = new DocumentDock { VisibleDockables = factory.CreateList() }; + var toolDock = new ToolDock { VisibleDockables = factory.CreateList() }; + + factory.AddDockable(root, documentDock); + factory.AddDockable(root, toolDock); + + var tool = new Tool { CanDockAsDocument = false }; + factory.AddDockable(toolDock, tool); + + factory.DockAsDocument(tool); + + Assert.Same(toolDock, tool.Owner); + Assert.DoesNotContain(tool, documentDock.VisibleDockables!); + } +} diff --git a/tests/Dock.Model.UnitTests/DockGroupValidationTests.cs b/tests/Dock.Model.UnitTests/DockGroupValidationTests.cs index 37f455876..c21d3f001 100644 --- a/tests/Dock.Model.UnitTests/DockGroupValidationTests.cs +++ b/tests/Dock.Model.UnitTests/DockGroupValidationTests.cs @@ -35,6 +35,7 @@ private class SimpleDockable : IDockable public bool CanFloat { get; set; } = true; public bool CanDrag { get; set; } = true; public bool CanDrop { get; set; } = true; + public bool CanDockAsDocument { get; set; } = true; public bool IsModified { get; set; } public string? DockGroup { get; set; } public IFactory? Factory { get; set; }