基于数据模板的上下文菜单项的不同格式

Different formatting on context menu items based on data template

我有一个可用的动态上下文菜单,但 XAML 格式似乎有问题。对我来说,似乎第一个选择的模板将用于所有菜单项。

我希望将图标放置在左侧突出显示列的正常标准位置,我仍然可以自定义右侧 XAML- 分别为每个菜单项定义的内容在他们的 DataTemplate.

这里是 XAML 代码片段,与 ListBox

一起使用
<ListBox.ContextMenu>
    <ContextMenu ItemsSource="{Binding ModelContextMenu}"
                 ItemTemplateSelector="{StaticResource ContextMenuItemDataTemplateSelector}">
    </ContextMenu>
</ListBox.ContextMenu>

以及不同菜单项的数据模板:

  <DataTemplate x:Key="ChangeColorMenuItem" DataType="MenuItem">
    <DockPanel>
      <MenuItem Header="{Binding DisplayName}"
                Command="{Binding Command}">
      </MenuItem>
      <xctk:ColorPicker
        SelectedColor="{Binding DataContext.SelectedColor, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:View}}}"
        Margin="0,0,0,0" />
    </DockPanel>
  </DataTemplate>

  <DataTemplate x:Key="NormalMenuItem" DataType="MenuItem">
    <MenuItem Header="{Binding DisplayName}"
              Command="{Binding Command}">
      <MenuItem.Icon>
        <Image Source="{Binding Icon}"/>
      </MenuItem.Icon>
    </MenuItem>
  </DataTemplate>

最后是模板选择器 class:

public class ContextMenuItemDataTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        if (container is FrameworkElement element && item is ContextMenuCommand commandItem)
        {
            switch (commandItem.MenuType)
            {
                case ContextMenuType.Normal:
                    return
                        element.FindResource("NormalMenuItem") as DataTemplate;
                case ContextMenuType.ChangeColor:
                    return
                        element.FindResource("ChangeColorMenuItem") as DataTemplate;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        return null;
    }
}

编辑 1

每个 MenuItem 内容都封装在绑定到 ContextMenu 的列表中。集合中的对象确实包含每个 MenuItem 的所有数据,例如图标、显示名称和 ICommand.

public ObservableCollection<ContextMenuCommand> ModelContextMenu => _selectedModel.Commands;

编辑 2

在下图中用蓝色十字标记的所需(标准)图标位置:

问题似乎是两个内部 MenuItem 因为有问题的数据模板。 通过按以下方式定义 ItemTemplate 和自定义 ItemContainerStyle 解决了该问题:

DataTemplates

<DataTemplate x:Key="ChangeColorMenuItem" DataType="MenuItem">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="0"
            Text="{Binding DisplayName}"
            Padding="5,0,5,0"/>
        <xctk:ColorPicker Grid.Column="1"
            SelectedColor="{Binding DataContext.SelectedEntityColor, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:PanelView}}}"
            Margin="0,0,0,0" />
    </Grid>
</DataTemplate>

<DataTemplate x:Key="NormalMenuItem" DataType="MenuItem">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="0"
            Text="{Binding DisplayName}" />
    </Grid>
</DataTemplate>

列表框上下文菜单

<ListBox.ContextMenu>
    <ContextMenu ItemsSource="{Binding CadModelContextMenu}"
        ItemTemplateSelector="{StaticResource PanelContextMenuItemDataTemplateSelector}"
        UsesItemContainerTemplate="True">
        <ContextMenu.Resources>
            <ResourceDictionary>
                <Image x:Key="menuIcon" x:Shared="false"
                    Source="{Binding Path=Icon}" Height="16px" Width="16px"/>
            </ResourceDictionary>
        </ContextMenu.Resources>
        <ContextMenu.ItemContainerStyle>
            <Style TargetType="{x:Type MenuItem}">
                <Setter Property="Icon" Value="{StaticResource menuIcon}"/>
                <Setter Property="Command" Value="{Binding Command}"/>
            </Style>
        </ContextMenu.ItemContainerStyle>
    </ContextMenu>
</ListBox.ContextMenu>

此解决方案的图标因每个项目而异。图标在底层对象的 属性 中定义。