diff --git a/src/Avalonia.Controls/SplitView/SplitView.cs b/src/Avalonia.Controls/SplitView/SplitView.cs index fd6fd98de6..f78ac6e0ee 100644 --- a/src/Avalonia.Controls/SplitView/SplitView.cs +++ b/src/Avalonia.Controls/SplitView/SplitView.cs @@ -314,6 +314,7 @@ namespace Avalonia.Controls { base.OnDetachedFromVisualTree(e); _pointerDisposable?.Dispose(); + _pointerDisposable = null; } /// @@ -423,7 +424,7 @@ namespace Avalonia.Controls protected virtual void OnPaneOpened(RoutedEventArgs args) { - EnableLightDismiss(); + InvalidateLightDismissSubscription(); RaiseEvent(args); } @@ -528,6 +529,8 @@ namespace Avalonia.Controls }; TemplateSettings.ClosedPaneWidth = closedPaneWidth; TemplateSettings.PaneColumnGridLength = paneColumnGridLength; + + InvalidateLightDismissSubscription(); } private void UpdateVisualStateForPanePlacementProperty(SplitViewPanePlacement newValue) @@ -541,7 +544,7 @@ namespace Avalonia.Controls PseudoClasses.Add(_lastPlacementPseudoclass); } - private void EnableLightDismiss() + private void InvalidateLightDismissSubscription() { if (_pane == null) return; @@ -549,19 +552,26 @@ namespace Avalonia.Controls // If this returns false, we're not in Overlay or CompactOverlay DisplayMode // and don't need the light dismiss behavior if (!IsInOverlayMode()) + { + _pointerDisposable?.Dispose(); + _pointerDisposable = null; return; + } - var topLevel = TopLevel.GetTopLevel(this); - if (topLevel != null) + if (_pointerDisposable == null) { - _pointerDisposable = Disposable.Create(() => + var topLevel = TopLevel.GetTopLevel(this); + if (topLevel != null) { - topLevel.PointerReleased -= PointerReleasedOutside; - topLevel.BackRequested -= TopLevelBackRequested; - }); - - topLevel.PointerReleased += PointerReleasedOutside; - topLevel.BackRequested += TopLevelBackRequested; + _pointerDisposable = Disposable.Create(() => + { + topLevel.PointerReleased -= PointerReleasedOutside; + topLevel.BackRequested -= TopLevelBackRequested; + }); + + topLevel.PointerReleased += PointerReleasedOutside; + topLevel.BackRequested += TopLevelBackRequested; + } } } diff --git a/tests/Avalonia.Controls.UnitTests/SplitViewTests.cs b/tests/Avalonia.Controls.UnitTests/SplitViewTests.cs index 47383fa9ad..896a088402 100644 --- a/tests/Avalonia.Controls.UnitTests/SplitViewTests.cs +++ b/tests/Avalonia.Controls.UnitTests/SplitViewTests.cs @@ -303,5 +303,45 @@ namespace Avalonia.Controls.UnitTests Assert.Contains(splitView.Classes, ":closed".Equals); } + + [Fact] + public void SplitView_Shouldnt_Close_Panel_When_IsPaneOpen_True_Then_Display_Mode_Changed() + { + using var app = UnitTestApplication.Start(TestServices.StyledWindow + .With(globalClock: new MockGlobalClock())); + var wnd = new Window + { + Width = 1280, + Height = 720 + }; + var splitView = new SplitView(); + splitView.DisplayMode = SplitViewDisplayMode.CompactOverlay; + wnd.Content = splitView; + wnd.Show(); + + splitView.IsPaneOpen = true; + + splitView.RaiseEvent(new PointerReleasedEventArgs(splitView, + null, wnd, new Point(1270, 30), 0, + new PointerPointProperties(), + KeyModifiers.None, + MouseButton.Left)); + + Assert.False(splitView.IsPaneOpen); + + // Inline shouldn't close the pane + splitView.IsPaneOpen = true; + + // Change the display mode once the pane is already open. + splitView.DisplayMode = SplitViewDisplayMode.Inline; + + splitView.RaiseEvent(new PointerReleasedEventArgs(splitView, + null, wnd, new Point(1270, 30), 0, + new PointerPointProperties(), + KeyModifiers.None, + MouseButton.Left)); + + Assert.True(splitView.IsPaneOpen); + } } }