如何更改 WPF 菜单的图标列大小?

Rob*_*Rob 3 wpf xaml menu wpf-controls

我有一个 WPF ContextMenu 看起来像这样:

<ContextMenu Width="300">
    <MenuItem Command="{Binding MainWindowViewModel.NewCommand}">
       <MenuItem.Icon>
           <Image Source="pack://application:,,,/EAV.UI;component/Resources/Icons/MenuNew.png" Width="32" Height="32"/>
       </MenuItem.Icon>
       <MenuItem.HeaderTemplate>
           <DataTemplate>
              <TextBlock Text="New" HorizontalAlignment="Left" VerticalAlignment="Center"/>
           </DataTemplate>
       </MenuItem.HeaderTemplate>
    </MenuItem>
</ContextMenu>
Run Code Online (Sandbox Code Playgroud)

问题是图标与图标列重叠,如下所示: 图标对于菜单来说太大

如何增加菜单图标列的宽度,以便大图标在列内居中?

Fre*_*lad 5

这只是一种解决方法,但它适用于 MenuItem 列的每个宽度。
结果将从此改变

替代文字

至此

替代文字

菜单中的所有内容都是动态构建的,除了菜单的图标“列”
使用 Snoop 我们可以看到它实际上是由三个矩形组成的

替代文字

第一个矩形的宽度为 28
第二个矩形的宽度为 1,边距为 (29, 2, 0, 2)
第三个矩形的宽度为 1,边距为 (30, 2, 0, 2)

我通过为最宽的菜单图标添加一个 Loaded 事件来解决这个问题。

<ContextMenu Width="300">  
    <MenuItem Command="{Binding MainWindowViewModel.NewCommand}">  
        <MenuItem.Icon>  
            <Image Source="pack://application:,,,/EAV.UI;component/Resources/Icons/MenuNew.png"
                   Width="32"
                   Height="32"
                   Loaded="WidestImage_Loaded"/>
       </MenuItem.Icon>  
       <MenuItem.HeaderTemplate>  
           <DataTemplate>  
               <TextBlock Text="New" HorizontalAlignment="Left" VerticalAlignment="Center"/>  
           </DataTemplate>  
       </MenuItem.HeaderTemplate>  
    </MenuItem>  
</ContextMenu>  
Run Code Online (Sandbox Code Playgroud)

然后像这样更改三个矩形的宽度和边距。

更新
正如 unforgiven3 所指出的,.NET 3.5 的可视化树看起来有点不同,此更新将解决这个问题。

private void WidestImage_Loaded(object sender, RoutedEventArgs e)
{
    Image image = sender as Image;
    StackPanel parentStackPanel = VisualTreeHelpers.GetVisualParent<StackPanel>(image);
    Grid grid = VisualTreeHelpers.GetVisualParent<Grid>(parentStackPanel);
    List<Rectangle> rectangles = VisualTreeHelpers.Get1stLevelVisualChildCollection<Rectangle>(grid);
    // .NET 3.5 fix
    if (rectangles.Count == 0)
    {
        ScrollViewer scrollViewer = VisualTreeHelpers.GetVisualParent<ScrollViewer>(grid);
        grid = VisualTreeHelpers.GetVisualParent<Grid>(scrollViewer);
        rectangles = VisualTreeHelpers.Get1stLevelVisualChildCollection<Rectangle>(grid);
    }

    double width = Math.Max(28, image.Width + 4);
    // 28
    rectangles[0].Width = width;
    // 28+1 = 29
    rectangles[1].Margin = new Thickness(width+1, 2, 0, 2);
    // 28+2 = 30
    rectangles[2].Margin = new Thickness(width+2, 2, 0, 2);
}
Run Code Online (Sandbox Code Playgroud)

以及一些 VisualTree Helper 方法的实现

public static T GetVisualParent<T>(object childObject) where T : Visual
{
    DependencyObject child = childObject as DependencyObject;
    // iteratively traverse the visual tree
    while ((child != null) && !(child is T))
    {
        child = VisualTreeHelper.GetParent(child);
    }
    return child as T;
}
public static List<T> Get1stLevelVisualChildCollection<T>(object parent) where T : Visual
{
    List<T> visualCollection = new List<T>();
    Get1stLevelVisualChildCollection(parent as DependencyObject, visualCollection);
    return visualCollection;
}
private static void Get1stLevelVisualChildCollection<T>(DependencyObject parent, List<T> visualCollection) where T : Visual
{
    int count = VisualTreeHelper.GetChildrenCount(parent);
    for (int i = 0; i < count; i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(parent, i);
        if (child is T)
        {
            visualCollection.Add(child as T);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)