当其所有子项都被禁用时,如何禁用顶级 WPF MenuItem?

发布于 2024-11-06 20:44:13 字数 764 浏览 0 评论 0原文

我的 WPF 应用程序中的上下文菜单中有以下 MenuItem:

<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>

问题是,当两个电子邮件命令都返回 CanExecute = false 时,因此这两个命令都被禁用,顶级 MenuItem“电子邮件”仍保持启用状态。我知道我可能可以将顶部菜单项的 IsEnabled 绑定到其 Children 属性,然后使用转换器来决定何时应禁用它,但似乎这应该自动发生。这不是使用 CommandBindings 的全部意义吗(即它们为您处理 IsEnabled)?有更好的方法来实现这一点吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

瀟灑尐姊 2024-11-13 20:44:13

我可以想到两种方法来做到这一点:

1)如果您不介意后面的代码(我尝试使用 WPF 避免这种情况),您可以为 IsEnabledChanged 创建一个事件处理程序来检查 IsEnabled 属性是否设置为 false。如果是的话,您可以执行类似

ParentMenuItem.IsEnabled = ParentMenuItem.Items.Count( c => c is MenuItem && (c as MenuItem).IsEnabled == true) > 0

2) 为父菜单项和子菜单项类型创建 ViewModel 并将父菜单项视图的 is Enabled 绑定到视图模型的 IsEnabled 属性的操作。视图模型将使用类似的方法返回 false

this.Children.Count(c => c.IsEnabled == true) > 0

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
花心好男孩 2024-11-13 20:44:13

为什么你的“电子邮件”菜单项应该被禁用?仅仅因为孩子们是?

我认为您使用多重绑定和转换器的方法是实现您想要的功能的好方法。

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.

双马尾 2024-11-13 20:44:13

定义一个 RootMenu 命令,然后将其添加到根菜单

Header="Email" Command="Commands:CommandRepository.RootMenu" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=.}"   

将命令绑定到下面的 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; }
        }
    }

它有点消耗 cpu 资源,但它可以工作。
不要有太多的 MenuItem 子项

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文