How do I get a top-level WPF MenuItem to be disabled when all its children are disabled?
I have the following MenuItem inside of a Context Menu in my WPF application:
<MenuItem Header="Email">
<MenuItem Command="Commands:CommandRepository.GenerateUserEmailCommand"
CommandParameter="{Binding Path=SelectedItems}"
Header="Email User">
</MenuItem>
<MenuItem Command="Commands:CommandRepository.GenerateManagerEmailCommand"
CommandParameter="{Binding Path=SelectedItems}"
Header="Email Manager">
</MenuItem>
</MenuItem>
The issue is that when both of the Email commands return CanExecute = false, and 开发者_运维技巧therefore both commands get disabled, the top-level MenuItem "Email" remains enabled. I know I could probably bind the IsEnabled of the top menu item to its Children property and then use a converter to decide when it should be disabled, but it seems like this should be happening automatically. Isn't this the whole point of using CommandBindings (i.e. they take care of IsEnabled for you)? Any better way to accomplish this?
I can think of two ways to do this:
1) If you don't mind code behind (I try to avoid it with WPF) you could just create an event handler for IsEnabledChanged that checks if the IsEnabled Property was set to false. If it was you could then do something like
ParentMenuItem.IsEnabled = ParentMenuItem.Items.Count( c => c is MenuItem && (c as MenuItem).IsEnabled == true) > 0
2) Create a ViewModel for the Parent MenuItem and Child MenuItem types and bind the is Enabled of the Parent MenuItem View to a IsEnabled property of the view model. The view model would return false using a similar
this.Children.Count(c => c.IsEnabled == true) > 0
why should your "Email" MenuItem become disabled? just because the childrens are?
i think your approach to use multibinding and a converter is a good way to do what YOU want.
Define a RootMenu command then add it to the root menu
Header="Email" Command="Commands:CommandRepository.RootMenu" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=.}"
Bind the command to the following RootMenuCanExecute
public static void DropDownMenuCanExecute(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = false;
ItemsControl parent = e.Parameter as ItemsControl;
if (parent.Items.Count == 0) { return; }
foreach (var i in parent.Items) {
ICommandSource cs = i as ICommandSource; if (cs==null) { continue; }
if (cs.Command == null) { continue; }
if (cs.Command.CanExecute(cs.CommandParameter)) { e.CanExecute = true; return; }
}
}
it is somewhat cpu expensive but it works. Whatch out not to have too many MenuItem children
精彩评论