fix(dock): ensure transactional tear-off and wire main window tabs
This commit is contained in:
@@ -299,23 +299,32 @@ public sealed partial class DockLayout : Control
|
||||
|
||||
private void TabView_TabDroppedOutside(Microsoft.UI.Xaml.Controls.TabView sender, Microsoft.UI.Xaml.Controls.TabViewTabDroppedOutsideEventArgs args)
|
||||
{
|
||||
if (_sourceNode != null && _draggedItem != null)
|
||||
if (_sourceNode != null && _draggedItem != null && TabTornOff != null)
|
||||
{
|
||||
int originalIndex = _sourceNode.Items.IndexOf(_draggedItem);
|
||||
if (originalIndex == -1)
|
||||
{
|
||||
ClearDragOperationState();
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove from current tree
|
||||
if (_sourceNode.Items.Remove(_draggedItem))
|
||||
{
|
||||
DockMutationEngine.CleanupEmptyNodes(_sourceNode);
|
||||
|
||||
try
|
||||
{
|
||||
// Raise event to let the host handle window creation
|
||||
TabTornOff?.Invoke(this, new TabTornOffEventArgs(_draggedItem));
|
||||
TabTornOff.Invoke(this, new TabTornOffEventArgs(_draggedItem));
|
||||
|
||||
// Only cleanup if the tear-off was successful (didn't throw)
|
||||
DockMutationEngine.CleanupEmptyNodes(_sourceNode);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Rollback: Re-insert the item if the tear-off handler fails
|
||||
_sourceNode.Items.Add(_draggedItem);
|
||||
Logger.LogError($"Failed to tear off tab: {ex.Message}");
|
||||
// Rollback: Re-insert the item at original position if the tear-off handler fails
|
||||
_sourceNode.Items.Insert(originalIndex, _draggedItem);
|
||||
_sourceNode.SelectedItem = _draggedItem;
|
||||
Logger.LogError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,10 +79,12 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ghost:NavigationTabView
|
||||
x:Name="PART_HierarchyTabView"
|
||||
Grid.Column="0"
|
||||
Width="350"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
VerticalAlignment="Stretch"
|
||||
TabDroppedOutside="OnTabDroppedOutside">
|
||||
<ghost:NavigationTabView.TabItems>
|
||||
<TabViewItem Header="Hierarchy">
|
||||
<TabViewItem.IconSource>
|
||||
@@ -93,7 +95,10 @@
|
||||
</ghost:NavigationTabView.TabItems>
|
||||
</ghost:NavigationTabView>
|
||||
|
||||
<ghost:NavigationTabView Grid.Column="1">
|
||||
<ghost:NavigationTabView
|
||||
x:Name="PART_SceneTabView"
|
||||
Grid.Column="1"
|
||||
TabDroppedOutside="OnTabDroppedOutside">
|
||||
<ghost:NavigationTabView.TabItems>
|
||||
<ee:ScenePage Header="Scene">
|
||||
<ee:ScenePage.IconSource>
|
||||
@@ -104,10 +109,12 @@
|
||||
</ghost:NavigationTabView>
|
||||
|
||||
<ghost:NavigationTabView
|
||||
x:Name="PART_InspectorTabView"
|
||||
Grid.Column="2"
|
||||
Width="350"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
VerticalAlignment="Stretch"
|
||||
TabDroppedOutside="OnTabDroppedOutside">
|
||||
<ghost:NavigationTabView.TabItems>
|
||||
<ee:InspectorPage Header="Inspector">
|
||||
<ee:InspectorPage.IconSource>
|
||||
@@ -118,7 +125,11 @@
|
||||
</ghost:NavigationTabView>
|
||||
</Grid>
|
||||
|
||||
<ghost:NavigationTabView Grid.Row="1" Height="350">
|
||||
<ghost:NavigationTabView
|
||||
x:Name="PART_BottomTabView"
|
||||
Grid.Row="1"
|
||||
Height="350"
|
||||
TabDroppedOutside="OnTabDroppedOutside">
|
||||
<ghost:NavigationTabView.TabItems>
|
||||
<TabViewItem Header="Project">
|
||||
<TabViewItem.IconSource>
|
||||
|
||||
@@ -35,17 +35,19 @@ internal sealed partial class EngineEditorWindow : WindowEx
|
||||
|
||||
SetTitleBar(PART_TitleBar);
|
||||
this.CenterOnScreen();
|
||||
|
||||
// Note: DockLayout is not directly in the XAML but created by RenderTree.
|
||||
// However, we can subscribe to the event if we find it or if it's exposed.
|
||||
// Since DockLayout is a TemplatePart or child of a Grid, we might need to wait for it.
|
||||
}
|
||||
|
||||
private void OnTabTornOff(object? sender, TabTornOffEventArgs e)
|
||||
private void OnTabDroppedOutside(Microsoft.UI.Xaml.Controls.TabView sender, Microsoft.UI.Xaml.Controls.TabViewTabDroppedOutsideEventArgs args)
|
||||
{
|
||||
var newWindow = new DockWindow(e.TabContent);
|
||||
App.AddSecondaryWindow(newWindow);
|
||||
newWindow.Activate();
|
||||
// For static tabs in EngineEditorWindow, we remove the item from TabItems
|
||||
if (sender.TabItems.Contains(args.Item))
|
||||
{
|
||||
sender.TabItems.Remove(args.Item);
|
||||
|
||||
var newWindow = new DockWindow(args.Item);
|
||||
App.AddSecondaryWindow(newWindow);
|
||||
newWindow.Activate();
|
||||
}
|
||||
}
|
||||
|
||||
private void MainGrid_Loaded(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
|
||||
Reference in New Issue
Block a user