开发者

How do I get a top-level WPF MenuItem to be disabled when all its children are disabled?

开发者 https://www.devze.com 2023-03-06 04:23 出处:网络
I have the following MenuItem inside of a Context Menu in my WPF application: <MenuItem Header=\"Email\">

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

0

精彩评论

暂无评论...
验证码 换一张
取 消