Browse Source

Fix SplitView incorrectly closing when the user changes DisplayMode to inline when IsPaneOpen is already true (#19460)

* add a failing unit test for issue #19457

* fix #19457 by invalidating the pointerReleased subscription when DisplayMode changes.

* [SplitView] ensure we always set _pointerDisposable to null when disposing.
release/11.3.4
Dan Walmsley 6 months ago
committed by Julien Lebosquain
parent
commit
7ea790189b
  1. 32
      src/Avalonia.Controls/SplitView/SplitView.cs
  2. 40
      tests/Avalonia.Controls.UnitTests/SplitViewTests.cs

32
src/Avalonia.Controls/SplitView/SplitView.cs

@ -314,6 +314,7 @@ namespace Avalonia.Controls
{
base.OnDetachedFromVisualTree(e);
_pointerDisposable?.Dispose();
_pointerDisposable = null;
}
/// <inheritdoc/>
@ -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;
}
}
}

40
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);
}
}
}

Loading…
Cancel
Save