【问题标题】:How do I change WPF Menu's icon column size?如何更改 WPF 菜单的图标列大小?
【发布时间】:2010-10-30 16:37:15
【问题描述】:

我有一个如下所示的 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>

问题是图标与图标列重叠,像这样:

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

【问题讨论】:

  • 似乎您需要更改 MenuItem 的模板。我建议使用 Blend 编辑模板或查看 Kaxaml 的 SimpleStyles。

标签: wpf xaml menu wpf-controls


【解决方案1】:

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

到这里

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

第一个矩形的宽度为 28
第二个矩形的宽度为 1,边距为 (29, 2, 0, 2)
第三个 Rectangle 的 Width 为 1,Margin 为 (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>  

然后像这样改变三个 Rectangle 的 Width 和 Margin。

更新
正如 unforgiven3 所指出的,.NET 3.5 的 Visual Tree 看起来有点不同,这次更新将解决这个问题。

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

【讨论】:

  • 视觉树对于 .NET 3.5 看起来有点不同。更新了我的答案。
猜你喜欢
  • 2015-11-17
  • 2011-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-10
  • 1970-01-01
  • 2014-01-26
相关资源
最近更新 更多