Skip to content

Commit e989b47

Browse files
grokysAnastassiaP
authored andcommitted
Fix MenuItem enabled state in the presence of sub-items. (#18679)
* Add unit test for sub menu item testing * Parent menu items should not be disabled on command binding failure. If a menu has a failed `Command` binding, but also has sub-menu items, then it should not be disabled. --------- Co-authored-by: Anastassia Pellja <[email protected]>
1 parent bb28298 commit e989b47

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

src/Avalonia.Controls/MenuItem.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Collections.Specialized;
34
using System.Linq;
45
using System.Windows.Input;
56
using Avalonia.Automation;
@@ -341,7 +342,7 @@ public string? GroupName
341342
/// <inheritdoc/>
342343
IMenuElement? IMenuItem.Parent => Parent as IMenuElement;
343344

344-
protected override bool IsEnabledCore => base.IsEnabledCore && _commandCanExecute;
345+
protected override bool IsEnabledCore => base.IsEnabled && (HasSubMenu || _commandCanExecute);
345346

346347
/// <inheritdoc/>
347348
bool IMenuElement.MoveSelection(NavigationDirection direction, bool wrap) => MoveSelection(direction, wrap);
@@ -710,6 +711,15 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
710711
{
711712
GroupNameChanged(change);
712713
}
714+
else if (change.Property == ItemCountProperty)
715+
{
716+
// A menu item with no sub-menu is effectively disabled if its command binding
717+
// failed: this means that the effectively enabled state depends on whether the
718+
// number of items in the menu is 0 or not.
719+
var (o, n) = change.GetOldAndNewValue<int>();
720+
if (o == 0 || n == 0)
721+
UpdateIsEffectivelyEnabled();
722+
}
713723
}
714724
/// <summary>
715725
/// Called when the <see cref="GroupName"/> property changes.

tests/Avalonia.Controls.UnitTests/MenuItemTests.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,45 @@ public void MenuItem_Is_Disabled_When_Bound_Command_Doesnt_Exist()
6262
Assert.False(target.IsEffectivelyEnabled);
6363
}
6464

65+
[Fact]
66+
public void MenuItem_With_Styled_Command_Binding_Should_Be_Enabled_With_Child_Missing_Command()
67+
{
68+
using var app = Application();
69+
70+
var viewModel = new MenuViewModel("Parent")
71+
{
72+
Children = [new MenuViewModel("Child")]
73+
};
74+
75+
var contextMenu = new ContextMenu
76+
{
77+
ItemsSource = new[] { viewModel },
78+
Styles =
79+
{
80+
new Style(x => x.OfType<MenuItem>())
81+
{
82+
Setters =
83+
{
84+
new Setter(MenuItem.HeaderProperty, new Binding("Header")),
85+
new Setter(MenuItem.ItemsSourceProperty, new Binding("Children")),
86+
new Setter(MenuItem.CommandProperty, new Binding("Command"))
87+
}
88+
}
89+
}
90+
};
91+
92+
var window = new Window { ContextMenu = contextMenu };
93+
window.Show();
94+
contextMenu.Open();
95+
96+
var parentMenuItem = Assert.IsType<MenuItem>(contextMenu.ContainerFromIndex(0));
97+
98+
Assert.Same(parentMenuItem.DataContext, viewModel);
99+
Assert.Same(parentMenuItem.ItemsSource, viewModel.Children);
100+
Assert.True(parentMenuItem.IsEnabled);
101+
Assert.True(parentMenuItem.IsEffectivelyEnabled);
102+
}
103+
65104
[Fact]
66105
public void MenuItem_Is_Disabled_When_Bound_Command_Is_Removed()
67106
{

0 commit comments

Comments
 (0)