如何使用ItemContainerStyle设置MenuItem的图标

dka*_*man 5 data-binding wpf icons mvvm menuitem

我正在遵循将a绑定MenuItem到数据对象的示例.

<Menu Grid.Row="0" KeyboardNavigation.TabNavigation="Cycle"
      ItemsSource="{Binding Path=MenuCommands}">  
    <Menu.ItemContainerStyle>
        <Style>
            <Setter Property="MenuItem.Header" Value="{Binding Path=DisplayName}"/>
            <Setter Property="MenuItem.ItemsSource" Value="{Binding Path=Commands}"/>
            <Setter Property="MenuItem.Command" Value="{Binding Path=Command}"/>
            <Setter Property="MenuItem.Icon" Value="{Binding Path=Icon}"/>
        </Style>
    </Menu.ItemContainerStyle>                
</Menu>
Run Code Online (Sandbox Code Playgroud)

这一切都在游泳,除了MenuItem图标显示为字符串System.Drawing.Bitmap.有问题的位图由数据对象从已编译的资源返回.

internal static System.Drawing.Bitmap folder_page
{
    get
    {
        object obj = ResourceManager.GetObject("folder_page", resourceCulture);
        return ((System.Drawing.Bitmap)(obj));
    }
}
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

cpl*_*tts 9

肯特(当然)有正确的答案.但我想我会继续发布转换器的代码,该转换器从System.Drawing.Bitmap(Windows窗体)转换为System.Windows.Windows.Media.BitmapSource(WPF) ......因为这是一个常见问题/题.

这需要三个步骤:

  1. 在绑定中使用图像转换器.
  2. 创建转换器.
  3. 在您的资源中声明转换器.

以下是如何在绑定中使用图像转换器:

<Setter
    Property="MenuItem.Icon"
    Value="{Binding Path=Icon, Converter={StaticResource imageConverter}}"
/>
Run Code Online (Sandbox Code Playgroud)

并且,这是转换器的代码(将其放入名为ImageConverter.cs的文件中)并将其添加到您的项目中:

[ValueConversion(typeof(Image), typeof(string))]
public class ImageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        BitmapSource bitmapSource;

        IntPtr bitmap = ((Bitmap)value).GetHbitmap();
        try
        {
            bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(bitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
        }
        finally
        {
            DeleteObject(bitmap);
        }

        return bitmapSource;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }

    [DllImport("gdi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    static extern int DeleteObject(IntPtr o);
}
Run Code Online (Sandbox Code Playgroud)

以下是在资源部分中声明它的方法(请注意您必须添加的本地命名空间):

<Window
    x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication2"
>
    <Window.Resources>
        <local:ImageConverter x:Key="imageConverter"/>
    </Window.Resources>
    <!-- some xaml snipped for clarity -->
</Window>
Run Code Online (Sandbox Code Playgroud)

就是这样!


更新

在快速搜索类似问题后,我注意到Lars Truijens指出前一个转换器实现泄漏.我已经更新了上面的转换器代码......这样它就不会泄漏.

有关泄漏原因的详细信息,请参阅此MSDN 链接上的备注部分.


Ken*_*art 5

WPF使用ImageSources而不是System.Drawing类.你需要绑定到ImageSource.您可以使用转换器将您转换Bitmap为a ImageSource,或者您可以放弃资源并以不同方式执行操作.