【问题标题】:Struggling to template a WPF MenuItem's Icon with control努力使用控件模板化 WPF MenuItem 的图标
【发布时间】:2017-08-30 14:33:13
【问题描述】:

继上一个问题here 之后,我正在努力使用我拥有的控件来设置MenuItemIcon 样式,该控件根据字符串依赖属性插入图标图像。

一开始我是:

<ContextMenu ItemsSource="{Binding MenuItems}">
    <ContextMenu.Resources>
        <Style TargetType="MenuItem">
            ...
            <Setter Property="Icon">
                <local:StringToIcon IconName="{Binding IconName}" />
            </Setter>
        </Style>
    </ContextMenu.Resources>
</ContextMenu>

这具有可预测的效果,即只显示菜单中的一个图标,通常是最后一个,因为实例是共享的。

然后我尝试了非共享资源的方法:

<ContextMenu ItemsSource="{Binding MenuItems}">
    <ContextMenu.Resources>
        <local:StringToIcon x:Key="MenuIcon" x:Shared="False" IconName="{Binding IconName}" />
        <Style TargetType="MenuItem">
            ...
            <Setter Property="Icon" Value="{StaticResource MenuIcon} />
        </Style>
    </ContextMenu.Resources>
</ContextMenu>

这没有效果。它没有在 Intellisense 中为我提供 x:Shared,所以我想知道这是否是无效属性。

无奈之下,我把东西扔进了模板:

<Setter Property="Icon">
    <Setter.Value>
        <ContentControl>
            <ContentControl.Template>
                <ControlTemplate>
                    <local:StringToIcon IconName="{Binding IconName}" />
                </ControlTemplate>
            </ContentControl.Template>
        </ContentControl>
    </Setter.Value>
</Setter>

再一次,没有效果。我的StringToIcon 目前看起来像这样,使用单个图像进行硬编码以检查问题是否存在。 (或者是吗?)

<UserControl x:Class="RAP.Admin3.Components.StringToIcon"
    ...
>
    <Image DataContext="{Binding ElementName=StringIconControl}" Source="pack://application:,,,/Resources/Icons/lorry.png"/>
</UserControl>

如何让这个该死的东西成为模板并允许多次使用?这可能是我忽略的基本内容。

我查看了各种类似的问题,大多数似乎都使用非共享资源方法取得了成功。

编辑:让我根据要求添加更多代码。我想出了这个问题的最小复制:

上下文菜单是 TreeView 资源的一部分。

<UserControl x:Class="MyApp.ItemHierarchy"
             ...
             Name="ItemHierarchyControl">
    <Grid>
        <TreeView ItemsSource="{Binding ElementName=ItemHierarchyControl, Path=Items}">
            <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type local:HierarchyItem}" ItemsSource="{Binding Subitems}">
                    <StackPanel Orientation="Horizontal" Margin="0,1,4,1">
                        <TextBlock Text="My text" VerticalAlignment="Center" />
                        <StackPanel.ContextMenu>
                            <ContextMenu ItemsSource="{Binding MenuItems}">
                                <ContextMenu.Resources>
                                    <local:StringToIcon x:Key="MenuIcon" x:Shared="False" IconName="{Binding IconName}" />
                                    <Style TargetType="MenuItem">
                                        <Setter Property="Header" Value="{Binding Path=Name}" />
                                        <Setter Property="Icon" Value="{StaticResource MenuIcon}" />
                                    </Style>
                                </ContextMenu.Resources>
                            </ContextMenu>
                        </StackPanel.ContextMenu>
                    </StackPanel>
                </HierarchicalDataTemplate>
            </TreeView.Resources>
        </TreeView>
    </Grid>
</UserControl>

这由项目的依赖属性支持。

public ObservableCollection<HierarchyItem> Items
{
    get { return (ObservableCollection<HierarchyItem>)GetValue(ItemsProperty); }
    set { SetValue(ItemsProperty, value); }
}

public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register("Items", typeof(ObservableCollection<HierarchyItem>), typeof(ItemHierarchy), new PropertyMetadata(new ObservableCollection<HierarchyItem>()));

StringToIcon 还由图标名称的字符串依赖属性支持,由于目前是硬编码的图像,该属性被立即忽略。

HierarchyItems 的例子很简单:

public ObservableCollection<HierarchyItem> Subitems { get; set; }
public ObservableCollection<BindableMenuItem> MenuItems { get; set; }

为了让这个证明有效,我将ItemHierarchy 附加到主窗口的一些属性中:

public ObservableCollection<BindableMenuItem> MenuItems { get; set; }
public ObservableCollection<HierarchyItem> IHItems { get; set; }
public MainWindow()
{
    MenuItems = new ObservableCollection<BindableMenuItem>();
    MenuItems.Add(new BindableMenuItem("Item", null));
    MenuItems.Add(new BindableMenuItem("Item", null));
    MenuItems.Add(new BindableMenuItem("Item", null));
    MenuItems.Add(new BindableMenuItem("Item", null));

    IHItems = new ObservableCollection<HierarchyItem>();
    IHItems.Add(new HierarchyItem() { MenuItems = this.MenuItems });

    InitializeComponent();
}

编辑 2:这里也是 BindableMenuItem

public class BindableMenuItem
{
    public BindableMenuItem(string name, ICommand command)
    {
        this.Name = name;
        this.Command = command;
    }
    public string Name { get; set; }
    public ICommand Command { get; set; }
    public string IconName { get; set; }
    public ObservableCollection<BindableMenuItem> Children { get; set; }
}

【问题讨论】:

  • 您的非共享资源方法应该有效。提问时请提供您问题的完整回购:stackoverflow.com/help/how-to-ask
  • @mm8 你有什么特别想看代码的吗?非共享资源方法似乎不起作用。上下文菜单中的最后一个图标出现,但其他图标均未出现。减少条目数意味着显示的图标向上移动。
  • “似乎不起作用”恐怕没有多大帮助。它对我有用,但我当然不能运行你的代码,因为你还没有发布它。
  • @mm8 我已在其用户控件中添加了上下文菜单的完整上下文,并将内容缩减为最小的可行示例。这有帮助吗?让我知道是否需要任何较小的元素。
  • 您不使用转换器是否有原因?在我看来,您正在尝试做一些非常简单的事情并且陷入了死胡同。为什么不简单地使用转换器将视图模型字符串转换为图标。我会发布一个解决方案,但我担心我没有充分解开你的问题,无法弄清楚这是否是你想要做的。

标签: c# wpf


【解决方案1】:

尝试将StringToIcon 移动到&lt;TreeView.Resources&gt;

<TreeView ItemsSource="{Binding ElementName=ItemHierarchyControl, Path=Items}">
    <TreeView.Resources>
        <local:StringToIcon x:Key="MenuIcon" x:Shared="False" IconName="{Binding IconName}" />
        <HierarchicalDataTemplate DataType="{x:Type local:HierarchyItem}" ItemsSource="{Binding Subitems}">
            <StackPanel Orientation="Horizontal" Margin="0,1,4,1">
                <TextBlock Text="My text" VerticalAlignment="Center" />
                <StackPanel.ContextMenu>
                    <ContextMenu ItemsSource="{Binding MenuItems}">
                        <ContextMenu.Resources>
                            <Style TargetType="MenuItem">
                                <Setter Property="Header" Value="{Binding Path=Name}" />
                                <Setter Property="Icon" Value="{StaticResource MenuIcon}" />
                            </Style>
                        </ContextMenu.Resources>
                    </ContextMenu>
                </StackPanel.ContextMenu>
            </StackPanel>
        </HierarchicalDataTemplate>
    </TreeView.Resources>
</TreeView>

【讨论】:

  • 天哪,是这样吗?谢谢!我排除了将它移到那里的可能性,因为我认为 IconName 绑定不起作用,因为上下文将是 TreeView。绑定是否在使用资源的上下文中进行评估?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多