Browse Source
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 <anyka545@gmail.com>
pull/18690/head
Steven Kirk
10 months ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with
50 additions and
1 deletions
src/Avalonia.Controls/MenuItem.cs
tests/Avalonia.Controls.UnitTests/MenuItemTests.cs
@ -1,5 +1,6 @@
using System ;
using System.Collections.Generic ;
using System.Collections.Specialized ;
using System.Linq ;
using System.Windows.Input ;
using Avalonia.Automation ;
@ -341,7 +342,7 @@ namespace Avalonia.Controls
/// <inheritdoc/>
IMenuElement ? IMenuItem . Parent = > Parent as IMenuElement ;
protected override bool IsEnabledCore = > base . IsEnabledCore & & _ commandCanExecute ;
protected override bool IsEnabledCore = > base . IsEnabled & & ( HasSubMenu | | _ commandCanExecute ) ;
/// <inheritdoc/>
bool IMenuElement . MoveSelection ( NavigationDirection direction , bool wrap ) = > MoveSelection ( direction , wrap ) ;
@ -710,6 +711,15 @@ namespace Avalonia.Controls
{
GroupNameChanged ( change ) ;
}
else if ( change . Property = = ItemCountProperty )
{
// A menu item with no sub-menu is effectively disabled if its command binding
// failed: this means that the effectively enabled state depends on whether the
// number of items in the menu is 0 or not.
var ( o , n ) = change . GetOldAndNewValue < int > ( ) ;
if ( o = = 0 | | n = = 0 )
UpdateIsEffectivelyEnabled ( ) ;
}
}
/// <summary>
/// Called when the <see cref="GroupName"/> property changes.
@ -62,6 +62,45 @@ namespace Avalonia.Controls.UnitTests
Assert . False ( target . IsEffectivelyEnabled ) ;
}
[Fact]
public void MenuItem_With_Styled_Command_Binding_Should_Be_Enabled_With_Child_Missing_Command ( )
{
using var app = Application ( ) ;
var viewModel = new MenuViewModel ( "Parent" )
{
Children = [ new MenuViewModel ( "Child" ) ]
} ;
var contextMenu = new ContextMenu
{
ItemsSource = new [ ] { viewModel } ,
Styles =
{
new Style ( x = > x . OfType < MenuItem > ( ) )
{
Setters =
{
new Setter ( MenuItem . HeaderProperty , new Binding ( "Header" ) ) ,
new Setter ( MenuItem . ItemsSourceProperty , new Binding ( "Children" ) ) ,
new Setter ( MenuItem . CommandProperty , new Binding ( "Command" ) )
}
}
}
} ;
var window = new Window { ContextMenu = contextMenu } ;
window . Show ( ) ;
contextMenu . Open ( ) ;
var parentMenuItem = Assert . IsType < MenuItem > ( contextMenu . ContainerFromIndex ( 0 ) ) ;
Assert . Same ( parentMenuItem . DataContext , viewModel ) ;
Assert . Same ( parentMenuItem . ItemsSource , viewModel . Children ) ;
Assert . True ( parentMenuItem . IsEnabled ) ;
Assert . True ( parentMenuItem . IsEffectivelyEnabled ) ;
}
[Fact]
public void MenuItem_Is_Disabled_When_Bound_Command_Is_Removed ( )
{