开发者

How do I change WPF Menu's icon column size?

开发者 https://www.devze.com 2023-01-22 22:57 出处:网络
I have a WPF ContextMenu that looks like this: <ContextMenu Width=\"300\"> 开发者_运维百科<MenuItem Command=\"{Binding MainWindowViewModel.NewCommand}\">

I have a WPF ContextMenu that looks like this:

<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>

The problem is that the icon overlaps the icon column, like this:

How do I change WPF Menu's icon column size?

How do I increase the width of the Menu's icon column so that the large icon is centered within the column?


This a just a workaround but it'll work for every width for a MenuItem's column.
The results will change from this

How do I change WPF Menu's icon column size?

To This

How do I change WPF Menu's icon column size?

Everything in the Menu is built dynamically except for the Menu's Icon "Column"
Using Snoop we can see that it's actually built up of three Rectangles

How do I change WPF Menu's icon column size?

The first Rectangle got a Width of 28
The second Rectangle got a Width of 1 and a Margin of (29, 2, 0, 2)
The third Rectangle got a Width of 1 and a Margin of (30, 2, 0, 2)

I fixed this by adding a Loaded event for the widest Menu Icon like this.

<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>  

And then changed the Width and Margin of the three Rectangles like this.

UPDATE
The Visual Tree was looking a little bit different for .NET 3.5 as pointed out by unforgiven3, this update will fix that.

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

And some implementation of the VisualTree Helper methods

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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号