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

标签 wpf xaml menu wpf-controls

我有一个如下所示的 WPF 上下文菜单:

<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

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

最佳答案

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

alt text

为此

alt text

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

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>  

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

更新
正如 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);
        }
    }
}

关于wpf - 如何更改 WPF 菜单的图标列大小?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4059626/

相关文章:

c# - 自定义 WPF 控件依赖属性未绑定(bind)到外部 DP

java - 选项菜单无法覆盖?

WPF 高度/宽度

c# - 如何获取和设置 WPF 文本框的当前光标位置

WPF MVVM 数据模板 : Inject Template ViewModel with Data from parent Viewmodel

c# - 基于 XSD 架构的 Wpf XmlDataProvider 验证

c# - 将 Dictionary<string,List<Class>> 绑定(bind)到 TreeView

java - android listview 也在迭代页脚菜单

HTML+CSS 垂直菜单及其旁边的 "news"框

c# - GridSplitter移至外部资源(UserControl)时的行为有所不同