Browse Source

Merge pull request #3480 from AvaloniaUI/fixes/3459-menu-keypress-nre

Fix NRE in Menu
foreign-embed-squash
Steven Kirk 7 years ago
committed by Dan Walmsley
parent
commit
14ecd58393
  1. 30
      src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
  2. 12
      tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs

30
src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs

@ -6,6 +6,8 @@ using Avalonia.LogicalTree;
using Avalonia.Rendering;
using Avalonia.Threading;
#nullable enable
namespace Avalonia.Controls.Platform
{
/// <summary>
@ -14,8 +16,8 @@ namespace Avalonia.Controls.Platform
public class DefaultMenuInteractionHandler : IMenuInteractionHandler
{
private readonly bool _isContextMenu;
private IDisposable _inputManagerSubscription;
private IRenderRoot _root;
private IDisposable? _inputManagerSubscription;
private IRenderRoot? _root;
public DefaultMenuInteractionHandler(bool isContextMenu)
: this(isContextMenu, Input.InputManager.Instance, DefaultDelayRun)
@ -24,9 +26,11 @@ namespace Avalonia.Controls.Platform
public DefaultMenuInteractionHandler(
bool isContextMenu,
IInputManager inputManager,
IInputManager? inputManager,
Action<Action, TimeSpan> delayRun)
{
delayRun = delayRun ?? throw new ArgumentNullException(nameof(delayRun));
_isContextMenu = isContextMenu;
InputManager = inputManager;
DelayRun = delayRun;
@ -92,7 +96,7 @@ namespace Avalonia.Controls.Platform
root.Deactivated -= WindowDeactivated;
}
_inputManagerSubscription.Dispose();
_inputManagerSubscription!.Dispose();
Menu = null;
_root = null;
@ -100,9 +104,9 @@ namespace Avalonia.Controls.Platform
protected Action<Action, TimeSpan> DelayRun { get; }
protected IInputManager InputManager { get; }
protected IInputManager? InputManager { get; }
protected IMenu Menu { get; private set; }
protected IMenu? Menu { get; private set; }
protected static TimeSpan MenuShowDelay { get; } = TimeSpan.FromMilliseconds(400);
@ -131,7 +135,7 @@ namespace Avalonia.Controls.Platform
KeyDown(GetMenuItem(e.Source as IControl), e);
}
protected internal virtual void KeyDown(IMenuItem item, KeyEventArgs e)
protected internal virtual void KeyDown(IMenuItem? item, KeyEventArgs e)
{
switch (e.Key)
{
@ -200,7 +204,7 @@ namespace Avalonia.Controls.Platform
}
else
{
Menu.Close();
Menu!.Close();
}
e.Handled = true;
@ -213,12 +217,12 @@ namespace Avalonia.Controls.Platform
{
if (item == null && _isContextMenu)
{
if (Menu.MoveSelection(direction.Value, true) == true)
if (Menu!.MoveSelection(direction.Value, true) == true)
{
e.Handled = true;
}
}
else if (item.Parent?.MoveSelection(direction.Value, true) == true)
else if (item?.Parent?.MoveSelection(direction.Value, true) == true)
{
// If the the parent is an IMenu which successfully moved its selection,
// and the current menu is open then close the current menu and open the
@ -408,7 +412,7 @@ namespace Avalonia.Controls.Platform
protected void CloseMenu(IMenuItem item)
{
var current = (IMenuElement)item;
var current = (IMenuElement?)item;
while (current != null && !(current is IMenu))
{
@ -456,7 +460,7 @@ namespace Avalonia.Controls.Platform
protected void SelectItemAndAncestors(IMenuItem item)
{
var current = item;
var current = (IMenuItem?)item;
while (current?.Parent != null)
{
@ -465,7 +469,7 @@ namespace Avalonia.Controls.Platform
}
}
protected static IMenuItem GetMenuItem(IControl item)
protected static IMenuItem? GetMenuItem(IControl? item)
{
while (true)
{

12
tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs

@ -199,6 +199,18 @@ namespace Avalonia.Controls.UnitTests.Platform
menu.VerifySet(x => x.SelectedItem = null, Times.Never);
Assert.False(e.Handled);
}
[Fact]
public void Doesnt_Throw_On_Menu_Keypress()
{
// Issue #3459
var target = new DefaultMenuInteractionHandler(false);
var menu = Mock.Of<IMenu>();
var item = Mock.Of<IMenuItem>(x => x.IsTopLevel == true && x.Parent == menu);
var e = new KeyEventArgs { Key = Key.Tab, Source = menu };
target.KeyDown(menu, e);
}
}
public class NonTopLevel

Loading…
Cancel
Save