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

时间:2010-10-30 16:37:15

标签: 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>

问题是图标与图标列重叠,如下所示: Icon is too big for menu

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

1 个答案:

答案 0 :(得分:4)

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

alt text

到此

alt text

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

alt text

第一个矩形的宽度为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>  

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

<强>更新
正如unforgiven3所指出的那样,Visual Tree看起来与.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);
}

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);
        }
    }
}