菜单项样式带有图标只会创建一个图标。

28

我遇到了一个问题,无法呈现动态菜单的图标,该菜单使用视图模型作为ItemsSource。
我使用的解决方案在这里概述: MVVM Dynamic Menu UI from binding with ViewModel

基本布局如下:

<Grid>
  <Grid.Resources>
    <HierarchicalDataTemplate DataType="{x:Type ViewModels:HeaderedItemViewModel}"
        ItemsSource="{Binding Path=Children}">
      <ContentPresenter RecognizesAccessKey="True"></ContentPresenter>
    </HierarchicalDataTemplate>
    <Style TargetType="{x:Type MenuItem}">
      <Setter Property="Header" Value="{Binding Path=Header}" />
      <Setter Property="InputGestureText" Value="{Binding Path=InputGestureText}" />
      <Setter Property="Command" Value="{Binding Path=Command}" />
      <Setter Property="Icon">
        <Setter.Value>
          <Image Source="{Binding Path=Icon}" Height="16px" Width="16px" />
        </Setter.Value>
      </Setter>
    </Style>
  </Grid.Resources>
  <Menu Grid.Row="0" ItemsSource="{Binding Path=Shell.Navigation.Menus}" />
</Grid>
在上述样式中,绑定的“Icon”是“ImageSource”。设置如下。
        BitmapImage image = null;

        if (!string.IsNullOrEmpty(imagePath))
        {
            image = new BitmapImage(new Uri(imagePath, UriKind.Relative));
            image.CacheOption = BitmapCacheOption.OnLoad;
            image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
        }
        var menu = new HeaderedItemViewModel
                       {
                           Header = header,
                           InputGestureText = inputGesture,
                           ImagePath = imagePath,
                           Icon = image,
                           Command = command,
                           IsEnabled = isEnabled
                       };
我遇到的问题是与图标有关的。
好像一次只能呈现一个图标?这就是我的意思。

在此输入图片描述

打开下拉菜单...

在此输入图片描述

只要另一个图像被呈现,第一个图像就会消失吗?换句话说,只有最后一个图像可见。这在菜单中的所有图像中都会发生。有什么想法吗?


一个问题:你如何设置实际的输入绑定?绑定到InputGestureText不会设置实际的输入绑定。 - bitbonk
我目前没有使用输入绑定。这可能会对你有所帮助。http://blogs.msdn.com/b/llobo/archive/2009/10/29/new-wpf-features-key-gesture-binding.aspx。通过扩展命令类,您可以将其映射到ViewModel的输入绑定集合中。 - bic
@bitbonk:是的,手势已按上述定义绑定。我有一个名为NavigationViewModel的类,它创建和初始化所有菜单和工具栏。这些都派生自一个名为HeaderItemViewModel的类。这意味着我可以重用在工具栏中也出现的菜单项实例。这回答了你的问题吗? - bic
2个回答

47

为图标值添加x:Shared=false。 要实现这一点,您需要在资源中声明Image:

<Grid>
  <Grid.Resources>

   <Image x:Key="imgCTX" x:Shared="false"
         Source="{Binding Path=Icon}" Height="16px" Width="16px"/>
    <HierarchicalDataTemplate DataType="{x:Type ViewModels:HeaderedItemViewModel}"
        ItemsSource="{Binding Path=Children}">
      <ContentPresenter RecognizesAccessKey="True"></ContentPresenter>
    </HierarchicalDataTemplate>
    <Style TargetType="{x:Type MenuItem}">
      <Setter Property="Header" Value="{Binding Path=Header}" />
      <Setter Property="InputGestureText" Value="{Binding Path=InputGestureText}" />
      <Setter Property="Command" Value="{Binding Path=Command}" />
      <Setter Property="Icon" Value="{StaticResource imgCTX}" />
    </Style>
  </Grid.Resources>
  <Menu Grid.Row="0" ItemsSource="{Binding Path=Shell.Navigation.Menus}" />
</Grid>

1
非常好,谢谢。不过有一个小问题,就是在图像资源中使用高度和宽度。这会导致顶级菜单扩展,即使它们没有图像。我想我可以重新调整图像大小并完成它。你有什么办法只在有图像可用时应用高度和宽度吗? - bic
我想我可以将它们添加到视图模型中并直接绑定它们,这可能是最简单的方法。 - bic
另外,你的回答中有一个错别字,“<Setter Property="Icon" Value="{StaticResource = imgCTX}" />” 应该改为 “<Setter Property="Icon" Value="{StaticResource imgCTX}" />”。 - bic
1
你是如何防止顶级菜单项根据底层菜单项的大小进行调整的? - MoonKnight
挽救了我的一天。谢谢。 - Vlad
今天我也遇到了同样的问题,你的答案解决了它。非常感谢! - lidqy

1

我已搜索了各种答复,x:Shared="false" 的设置确实有所帮助,但您还需要正确设置所有内容以确保其正常工作,并且我花了一些时间才找到适当的解决方案。以下是我这边的解决方法

        <ContextMenu ItemsSource="{Binding MenuElements}">
            <ContextMenu.Resources>
                <ControlTemplate x:Key="MenuSeparatorTemplate">
                    <Separator />
                </ControlTemplate>
                <Image
                    x:Key="MenuIcon"
                    Width="16"
                    Height="16"
                    x:Shared="False"
                    Source="{Binding Icon}" />
            </ContextMenu.Resources>
            <ContextMenu.ItemContainerStyle>
                <Style TargetType="{x:Type MenuItem}">
                    <Setter Property="Header" Value="{Binding Name}" />
                    <Setter Property="ItemsSource" Value="{Binding Childs}" />
                    <Setter Property="Command" Value="{Binding Run}" />
                    <Setter Property="Icon" Value="{StaticResource MenuIcon}" />
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsSeparator}" Value="true">
                            <Setter Property="Template" Value="{StaticResource MenuSeparatorTemplate}" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ContextMenu.ItemContainerStyle>
        </ContextMenu>

通过这种方式,我已经能够使我的上下文菜单根据输入动态加载图标。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接