I'm following the example here of binding a MenuItem
to a data object.
<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>
It all works swimmingly except the MenuItem
's icon shows up as the string System.Drawing.Bitmap
. The bitmap in question is returned by the data object from a compiled resource.
internal static System.Drawing.Bitmap folder_page
{
get
{
object obj = ResourceManager.GetObject("folder_page", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
What am I doing wrong?
Kent (of course) has the right answer. But I thought I would go ahead and post the code for the converter that converts from the System.Drawing.Bitmap (Windows Forms) to a System.Windows.Windows.Media.BitmapSource (WPF) ... as this is a common problem/question.
This takes three steps:
Here is how you would use an image converter in your binding:
<Setter
Property="MenuItem.Icon"
Value="{Binding Path=Icon, Converter={StaticResource imageConverter}}"
/>
And, here is the code for the converter (put it into a file called ImageConverter.cs) and add it to your project:
[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);
}
Here is how you declare it in your resources section (note the local namespace that you will have to add):
<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>
And that's it!
Update
After doing a quick search for similar questions, I noticed that Lars Truijens pointed out here that the previous converter implementation leaks. I have updated the converter code above ... so that it doesn't leak.
For more information on the cause of the leak, see the remarks section on this MSDN link.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With