Aprillz.MewUI.MewDock - A MewUI port of FlexLayout #166
Replies: 1 comment
-
MewDockA docking framework for MewUI: dockable document tabs and tool panes, drag-and-drop rearranging, splits,
Concepts
Quick startusing Aprillz.MewUI.MewDock;
var manager = new DockingManager
{
// Builds content for panes restored from a saved layout, keyed off DockPane.Component.
ContentFactory = pane => new TextBlock { Text = pane.Title },
};
// Load a layout (FlexLayout-compatible JSON).
manager.LoadLayout(layoutJson);
// Add panes at runtime with explicit content (bypasses ContentFactory).
manager.AddDocumentPane("Report", new ReportView());
manager.AddToolPane("Explorer", new ExplorerView(), DockEdge.Left);
// DockingManager is a Panel: drop it straight into a window.
var window = new Window().Resizable(1100, 740).Content(manager);
Application.Run(window);
|
| Member | Description |
|---|---|
LoadLayout(string json) |
Replace the layout from JSON. |
SaveLayout() : string |
Serialize the current layout (including dock sub-layouts and popouts). |
AddDocumentPane(string title, UIElement content, string? component = null) : DockPane |
Add a document tab to the center. |
AddToolPane(string title, UIElement content, DockEdge edge = Left, string? component = null) : DockPane |
Add a tool pane docked to an edge. |
ContentFactory : Func<DockPane, UIElement?>? |
Builds content for panes restored from a layout. |
HeaderTemplate : Func<DockPane, UIElement?>? |
Custom tab-header content; null uses the default header. |
CenterContent : UIElement? |
Replace the document host with a custom center element. |
ActivePane : DockPane? / ActiveGroup : DockGroup? |
The focused pane and its group. |
DocumentPanes / Panes : IReadOnlyList<DockPane> |
Document panes / tool panes. |
Groups : IReadOnlyList<DockGroup> |
Every tab group. |
ActivePaneChanged : EventHandler<DockPane?> |
Raised when focus moves to a different pane. |
Changed : EventHandler |
Raised after any layout change. |
DockPane (a handle)
A lightweight handle over one pane. It carries identity plus the common verbs; the layout itself stays inside
the manager.
| Member | Description |
|---|---|
Title (get/set) / Component |
Display title (setting it renames the tab) and the serialization key. |
IsDocument / IsActive |
Document pane vs tool pane; whether it is the active pane. |
Group : DockGroup? / Edge : DockEdge? |
The group it lives in (null when auto-hidden) and the edge it sits on. |
Content |
The element passed to AddDocumentPane/AddToolPane (null for factory-restored panes). |
Activate() / Close() |
Select or close the pane. |
Float() / FloatGroup() |
Pop the pane, or its whole group, out into a window. |
SplitOff(DockEdge) |
Split this pane off its own group toward an edge. |
MoveInto(DockGroup) / DockInto(DockGroup, DockEdge) |
Join another group as a tab / dock against one of its edges. |
Pin() / Unpin() |
Pin an auto-hide pane into a docked group, or send a docked group back to auto-hide. |
manager.ActivePane?.FloatGroup(); // pop the active group out
manager.Panes[0].Unpin(); // send a tool back to its auto-hide edgeDockEdge is Left | Top | Right | Bottom.
DockGroup (a handle)
A handle over one tab group (a tabset). Auto-hide borders are not groups, so an auto-hidden pane reports a null
Group.
| Member | Description |
|---|---|
IsDocument / IsMaximized |
Document group vs tool group; whether it is maximized. |
Edge : DockEdge? |
The edge the group is docked to (null for a document / floating group). |
Panes : IReadOnlyList<DockPane> / ActivePane : DockPane? |
The tabs in the group; the selected one. |
AddPane(string title, UIElement content, string? component = null) : DockPane |
Add a tab; the kind follows the group. |
Activate() / Close() |
Focus the group; close it and all its tabs. |
Float() |
Pop the whole group out into a window. |
ToggleMaximize() |
Maximize / restore (document groups only). |
Unpin() |
Send a docked tool group back to its auto-hide edge (tool groups only). |
Placement and lookup
Bootstrap vs group-level. DockingManager.AddDocumentPane / AddToolPane work even when no group exists yet -
they create one. So you always start at the manager level, and the returned DockPane's Group is the group that
was just created. You cannot create an empty group (an empty tabset is tidied away), so "create a group" is just
"add a pane".
var pane = manager.AddDocumentPane("First", new View()); // fine on an empty layout, creates the group
var group = pane.Group; // the new group
group.AddPane("Second", new View()); // add to the same group (kind follows the group)To target an existing group / pane:
DockGroup.AddPane(...)- add a tab to that group; the new tab's kind follows the group'sIsDocument.DockPane.MoveInto(group)/DockInto(group, edge)- move into another group / dock against one of its edges.
There is no lookup API - Panes / DocumentPanes / Groups are enumerable, so use LINQ:
var grid = manager.Panes.FirstOrDefault(p => p.Component == "grid");Layout JSON
LoadLayout / SaveLayout use a FlexLayout-compatible model. A tab is a document by default; mark it a pane
with "isDocument": false (auto-hide border tabs are stamped panes automatically).
{
"global": {},
"borders": [
{ "location": "left", "children": [
{ "type": "tab", "name": "Explorer", "component": "grid" }
]}
],
"layout": {
"type": "row",
"children": [
{ "type": "tabset", "weight": 60, "children": [
{ "type": "tab", "name": "Report", "component": "chart" }
]},
{ "type": "tabset", "weight": 40, "children": [
{ "type": "tab", "name": "Notes", "component": "notes", "enableClose": false }
]}
]
}
}Node ids are optional in JSON - MewDock assigns one when omitted and manages them internally (they are not part
of the public API; you address panes and groups through their handles, not ids).
Content and persistence
A pane gets its content one of two ways:
- Explicit content -
AddDocumentPane/AddToolPane/DockGroup.AddPanetake a live element, stored
against the pane and shown directly. It does not go throughContentFactory. - Factory content - a tab loaded from JSON carries a
componentkey. When the view needs its body it calls
ContentFactory(pane), and the host builds the element by readingpane.Component.
component is just a string the framework carries on the node and serializes; it does not map to content by
itself. The mapping lives in your ContentFactory (a switch or dictionary on pane.Component):
manager.ContentFactory = pane => pane.Component switch
{
"grid" => new GridView(),
"chart" => new ChartView(),
_ => new TextBlock { Text = pane.Title },
};Persistence follows from this: SaveLayout writes each tab's name and component, not its live element. So a
pane survives Save -> Load only if it has a component that ContentFactory can rebuild. The Add methods take
a component argument, so passing a key when you add gives you both immediate display (explicit content) and
round-trip restore (rebuilt from the key by ContentFactory):
manager.AddDocumentPane("Report", new ReportView(), component: "report"); // shown now + survives save/loadOmit component and the pane is shown immediately but is not restored after a round-trip (re-add it after
loading).
Localization
User-visible strings live in MewUIDockString as ObservableValue<string> (menus, tooltips, drag chips, the
unnamed-tab fallback). Defaults are English. Set .Value to translate; bound consumers (tooltips) update
immediately, transient ones (menus, drag chips) pick up the new value the next time they are shown.
MewUIDockString.MenuClose.Value = "닫기";
MewUIDockString.ToolTipClose.Value = "닫기";The empty center carries no text - put a start page or branding there via CenterContent if you want one.
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
The first MewUI docking prototype was based on Golden Layout, but Golden Layout had several structural limitations for the desktop docking behavior I wanted to support.
MewDockis now based on a customized port ofFlexLayout, originally a React component, and is being extended for MewUI’s desktop docking model.This is not a direct web-layout port. The implementation is being adapted for desktop-style docking, including separate handling for document panes and tool panes.
MewDockwill be introduced as a first-party MewUI extension control library, rather than being part of the core UI framework itself.This should provide a better foundation for IDE-like docking layouts in MewUI while keeping the core framework focused.
Beta Was this translation helpful? Give feedback.
All reactions