Browse Source

Use ContextRequested event to show ContextMenu

pull/6059/head
Max Katz 5 years ago
parent
commit
72c975ac0b
  1. 37
      src/Avalonia.Controls/ContextMenu.cs
  2. 6
      src/Avalonia.Controls/Control.cs
  3. 105
      tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs

37
src/Avalonia.Controls/ContextMenu.cs

@ -1,12 +1,15 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Avalonia.Controls.Generators;
using Avalonia.Controls.Platform;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Primitives.PopupPositioning;
using Avalonia.Controls.Templates;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Styling;
@ -220,7 +223,7 @@ namespace Avalonia.Controls
if (e.OldValue is ContextMenu oldMenu)
{
control.PointerReleased -= ControlPointerReleased;
control.ContextRequested -= ControlContextRequested;
oldMenu._attachedControls?.Remove(control);
((ISetLogicalParent?)oldMenu._popup)?.SetParent(null);
}
@ -229,7 +232,7 @@ namespace Avalonia.Controls
{
newMenu._attachedControls ??= new List<Control>();
newMenu._attachedControls.Add(control);
control.PointerReleased += ControlPointerReleased;
control.ContextRequested += ControlContextRequested;
}
}
@ -330,6 +333,7 @@ namespace Avalonia.Controls
_popup.Opened += PopupOpened;
_popup.Closed += PopupClosed;
_popup.Closing += PopupClosing;
_popup.KeyUp += PopupKeyUp;
}
if (_popup.Parent != control)
@ -389,25 +393,28 @@ namespace Avalonia.Controls
});
}
private static void ControlPointerReleased(object sender, PointerReleasedEventArgs e)
private void PopupKeyUp(object sender, KeyEventArgs e)
{
var control = (Control)sender;
var contextMenu = control.ContextMenu;
if (control.ContextMenu.IsOpen)
if (IsOpen)
{
if (contextMenu.CancelClosing())
return;
var keymap = AvaloniaLocator.Current.GetService<PlatformHotkeyConfiguration>();
control.ContextMenu.Close();
e.Handled = true;
if (keymap.OpenContextMenu.Any(k => k.Matches(e))
&& !CancelClosing())
{
Close();
e.Handled = true;
}
}
}
if (e.InitialPressMouseButton == MouseButton.Right)
private static void ControlContextRequested(object sender, ContextRequestedEventArgs e)
{
var control = (Control)sender;
if (!e.Handled
&& control.ContextMenu is ContextMenu contextMenu
&& !contextMenu.CancelOpening())
{
if (contextMenu.CancelOpening())
return;
contextMenu.Open(control, e.Source as Control ?? control);
e.Handled = true;
}

6
src/Avalonia.Controls/Control.cs

@ -231,7 +231,8 @@ namespace Avalonia.Controls
{
base.OnPointerReleased(e);
if (!e.Handled
if (e.Source == this
&& !e.Handled
&& e.InitialPressMouseButton == MouseButton.Right)
{
var args = new ContextRequestedEventArgs(e);
@ -244,7 +245,8 @@ namespace Avalonia.Controls
{
base.OnKeyUp(e);
if (!e.Handled)
if (e.Source == this
&& !e.Handled)
{
var keymap = AvaloniaLocator.Current.GetService<PlatformHotkeyConfiguration>().OpenContextMenu;
var matches = false;

105
tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs

@ -1,11 +1,11 @@
using System;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.LogicalTree;
using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.UnitTests;
using Castle.DynamicProxy.Generators;
using Moq;
using Xunit;
@ -123,6 +123,90 @@ namespace Avalonia.Controls.UnitTests
}
}
[Fact]
public void Cancel_Light_Dismiss_Closing_Keeps_Flyout_Open()
{
using (Application())
{
var renderer = new Mock<IRenderer>();
var platform = AvaloniaLocator.Current.GetService<IWindowingPlatform>();
var windowImpl = Mock.Get(platform.CreateWindow());
windowImpl.Setup(x => x.CreateRenderer(It.IsAny<IRenderRoot>())).Returns(renderer.Object);
var window = new Window(windowImpl.Object);
window.Width = 100;
window.Height = 100;
var button = new Button
{
Height = 10,
Width = 10,
HorizontalAlignment = Layout.HorizontalAlignment.Left,
VerticalAlignment = Layout.VerticalAlignment.Top
};
window.Content = button;
window.ApplyTemplate();
window.Show();
var tracker = 0;
var c = new ContextMenu();
c.ContextMenuClosing += (s, e) =>
{
tracker++;
e.Cancel = true;
};
button.ContextMenu = c;
c.Open(button);
var e = CreatePointerPressedEventArgs(window, new Point(90, 90));
var overlay = LightDismissOverlayLayer.GetLightDismissOverlayLayer(window);
overlay.RaiseEvent(e);
Assert.Equal(1, tracker);
Assert.True(c.IsOpen);
}
}
[Fact]
public void Light_Dismiss_Closes_Flyout()
{
using (Application())
{
var renderer = new Mock<IRenderer>();
var platform = AvaloniaLocator.Current.GetService<IWindowingPlatform>();
var windowImpl = Mock.Get(platform.CreateWindow());
windowImpl.Setup(x => x.CreateRenderer(It.IsAny<IRenderRoot>())).Returns(renderer.Object);
var window = new Window(windowImpl.Object);
window.Width = 100;
window.Height = 100;
var button = new Button
{
Height = 10,
Width = 10,
HorizontalAlignment = Layout.HorizontalAlignment.Left,
VerticalAlignment = Layout.VerticalAlignment.Top
};
window.Content = button;
window.ApplyTemplate();
window.Show();
var c = new ContextMenu();
c.PlacementMode = PlacementMode.Bottom;
c.Open(button);
var e = CreatePointerPressedEventArgs(window, new Point(90, 90));
var overlay = LightDismissOverlayLayer.GetLightDismissOverlayLayer(window);
overlay.RaiseEvent(e);
Assert.False(c.IsOpen);
}
}
[Fact]
public void Clicking_On_Control_Toggles_ContextMenu()
{
@ -341,7 +425,7 @@ namespace Avalonia.Controls.UnitTests
}
}
[Fact(Skip = "The only reason this test was 'passing' before was that the author forgot to call Window.ApplyTemplate()")]
[Fact]
public void Cancelling_Closing_Leaves_ContextMenuOpen()
{
using (Application())
@ -396,5 +480,18 @@ namespace Avalonia.Controls.UnitTests
return UnitTestApplication.Start(services);
}
private PointerPressedEventArgs CreatePointerPressedEventArgs(Window source, Point p)
{
var pointer = new Pointer(Pointer.GetNextFreeId(), PointerType.Mouse, true);
return new PointerPressedEventArgs(
source,
pointer,
source,
p,
0,
new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.LeftButtonPressed),
KeyModifiers.None);
}
}
}

Loading…
Cancel
Save