fix(dock): decouple DockLayout from window creation and remove redundant state
This commit is contained in:
@@ -297,18 +297,17 @@ public sealed partial class DockLayout : Control
|
|||||||
return tabView;
|
return tabView;
|
||||||
}
|
}
|
||||||
|
|
||||||
private object? _draggedItem;
|
|
||||||
private DockPosition _currentDropPosition = DockPosition.None;
|
private DockPosition _currentDropPosition = DockPosition.None;
|
||||||
|
|
||||||
private record DockDragPayload(object Item, DockPanelNode SourceNode);
|
private record DockDragPayload(object Item, DockPanelNode SourceNode);
|
||||||
|
|
||||||
|
public event EventHandler<TabTornOffEventArgs>? TabTornOff;
|
||||||
|
|
||||||
private void TabView_TabDragStarting(Microsoft.UI.Xaml.Controls.TabView sender, Microsoft.UI.Xaml.Controls.TabViewTabDragStartingEventArgs args)
|
private void TabView_TabDragStarting(Microsoft.UI.Xaml.Controls.TabView sender, Microsoft.UI.Xaml.Controls.TabViewTabDragStartingEventArgs args)
|
||||||
{
|
{
|
||||||
_draggedItem = args.Item;
|
if (args.Item != null && sender.Tag is DockPanelNode sourceNode)
|
||||||
|
|
||||||
if (_draggedItem != null && sender.Tag is DockPanelNode sourceNode)
|
|
||||||
{
|
{
|
||||||
var payload = new DockDragPayload(_draggedItem, sourceNode);
|
var payload = new DockDragPayload(args.Item, sourceNode);
|
||||||
args.Data.Properties.Add(DRAG_PROPERTY_DOCK_TAB, payload); // Identify our drag
|
args.Data.Properties.Add(DRAG_PROPERTY_DOCK_TAB, payload); // Identify our drag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -316,7 +315,7 @@ public sealed partial class DockLayout : Control
|
|||||||
private void TabView_DragOver(object sender, DragEventArgs e)
|
private void TabView_DragOver(object sender, DragEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.DataView.Properties.TryGetValue(DRAG_PROPERTY_DOCK_TAB, out var payloadObj) &&
|
if (e.DataView.Properties.TryGetValue(DRAG_PROPERTY_DOCK_TAB, out var payloadObj) &&
|
||||||
payloadObj is DockDragPayload payload &&
|
payloadObj is DockDragPayload &&
|
||||||
sender is FrameworkElement targetElement)
|
sender is FrameworkElement targetElement)
|
||||||
{
|
{
|
||||||
e.AcceptedOperation = global::Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move;
|
e.AcceptedOperation = global::Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move;
|
||||||
@@ -349,7 +348,6 @@ public sealed partial class DockLayout : Control
|
|||||||
private void ClearDragOperationState()
|
private void ClearDragOperationState()
|
||||||
{
|
{
|
||||||
ClearOverlayState();
|
ClearOverlayState();
|
||||||
_draggedItem = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateDropOverlay(FrameworkElement targetElement, DockPosition position)
|
private void UpdateDropOverlay(FrameworkElement targetElement, DockPosition position)
|
||||||
@@ -441,6 +439,9 @@ public sealed partial class DockLayout : Control
|
|||||||
|
|
||||||
if (result.IsSuccess)
|
if (result.IsSuccess)
|
||||||
{
|
{
|
||||||
|
// Raise event to let the host handle window creation
|
||||||
|
TabTornOff?.Invoke(this, new TabTornOffEventArgs(args.Item, sourceNode));
|
||||||
|
|
||||||
DockMutationEngine.CleanupEmptyNodes(sourceNode);
|
DockMutationEngine.CleanupEmptyNodes(sourceNode);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -10,8 +10,14 @@ public sealed class TabTornOffEventArgs : EventArgs
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public object TabContent { get; }
|
public object TabContent { get; }
|
||||||
|
|
||||||
public TabTornOffEventArgs(object tabContent)
|
/// <summary>
|
||||||
|
/// Gets the source node the tab is being torn off from.
|
||||||
|
/// </summary>
|
||||||
|
public object SourceNode { get; }
|
||||||
|
|
||||||
|
public TabTornOffEventArgs(object tabContent, object sourceNode)
|
||||||
{
|
{
|
||||||
TabContent = tabContent;
|
TabContent = tabContent;
|
||||||
|
SourceNode = sourceNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,5 +17,13 @@ internal sealed partial class DockWindow : WindowEx
|
|||||||
rootGroup.AddChild(panel);
|
rootGroup.AddChild(panel);
|
||||||
|
|
||||||
PART_DockLayout.Root = rootGroup;
|
PART_DockLayout.Root = rootGroup;
|
||||||
|
PART_DockLayout.TabTornOff += OnTabTornOff;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTabTornOff(object? sender, TabTornOffEventArgs e)
|
||||||
|
{
|
||||||
|
App.CreateAndShowDockWindow(e.TabContent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -45,7 +45,11 @@ internal sealed partial class EngineEditorWindow : WindowEx
|
|||||||
{
|
{
|
||||||
var result = TabTearOffService.TryTearOffTab(list, args.Item, sender);
|
var result = TabTearOffService.TryTearOffTab(list, args.Item, sender);
|
||||||
|
|
||||||
if (!result.IsSuccess)
|
if (result.IsSuccess)
|
||||||
|
{
|
||||||
|
App.CreateAndShowDockWindow(args.Item);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
Logger.LogWarning($"Tab tear-off failed: {result.Message}");
|
Logger.LogWarning($"Tab tear-off failed: {result.Message}");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ internal static class TabTearOffService
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
App.CreateAndShowDockWindow(tabItem);
|
// We no longer create the window here to decouple the service from the app shell.
|
||||||
|
// The caller is responsible for window creation (e.g. via an event handler).
|
||||||
return Result.Success();
|
return Result.Success();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -49,10 +50,10 @@ internal static class TabTearOffService
|
|||||||
catch (Exception rollbackEx)
|
catch (Exception rollbackEx)
|
||||||
{
|
{
|
||||||
Logger.LogError(rollbackEx);
|
Logger.LogError(rollbackEx);
|
||||||
return Result.Failure($"Failed to create tear-off window and rollback failed: {ex.Message}. Rollback error: {rollbackEx.Message}");
|
return Result.Failure($"Failed to tear off tab and rollback failed: {ex.Message}. Rollback error: {rollbackEx.Message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.Failure($"Failed to create tear-off window: {ex.Message}");
|
return Result.Failure($"Failed to tear off tab: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
Reference in New Issue
Block a user