代码之家  ›  专栏  ›  技术社区  ›  Rob

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

  •  3
  • Rob  · 技术社区  · 15 年前

    <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 回复  |  直到 15 年前
        1
  •  4
  •   Fredrik Hedblad    15 年前

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

    alt text

    alt text

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

    alt text

    第一个矩形的宽度是28

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

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

    <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所指出的,对于.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助手方法的一些实现

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