我正在遵循将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>
除了MenuItem
的图标显示为字符串System.Drawing.Bitmap
之外,它全部都有效。有问题的位图由数据对象从已编译的资源返回。
internal static System.Drawing.Bitmap folder_page
{
get
{
object obj = ResourceManager.GetObject("folder_page", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
我做错了什么?
答案 0 :(得分:9)
肯特(当然)有正确的答案。 但我想我会继续发布转换器的代码,该转换器从System.Drawing.Bitmap(Windows窗体)转换为System.Windows.Windows.Media.BitmapSource(WPF)。因为这是一个常见的问题/问题。
这需要三个步骤:
以下是如何在绑定中使用图像转换器:
<Setter
Property="MenuItem.Icon"
Value="{Binding Path=Icon, Converter={StaticResource imageConverter}}"
/>
并且,以下是转换器的代码(将其放入名为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);
}
以下是您在资源部分中声明的方式(请注意您必须添加的本地命名空间):
<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>
就是这样!
<强>更新强>
在快速搜索类似问题后,我注意到Lars Truijens指出here前一个转换器实现泄漏。我已经更新了上面的转换器代码......这样它就不会泄漏。
有关泄漏原因的详细信息,请参阅此MSDN上的备注部分link。
答案 1 :(得分:5)
WPF适用于ImageSource
,而非System.Drawing
类。您需要绑定到ImageSource
。您可以使用转换器将Bitmap
转换为ImageSource
,或者您可以放弃资源并以不同方式执行操作。
答案 2 :(得分:1)
WPF的menuitems有些奇怪,因为他们不使用ImageSource对象,就像WPF框架的其余部分一样。
最容易让您头痛的方法就是在viewmodel中添加一个返回完整Image控件的属性:
public Image MenuIcon
{
get
{
return new Image()
{
Source = CreateImageSource("myImage.png")
};
}
}
然后在你的<Style>
菜单项中(例如,您可以在ItemContainerStyle中设置),只需将菜单项的Icon
属性绑定到MenuIcon
属性即可。你的viewmodel:
<Setter Property="Icon" Value="{Binding MenuIcon}" />
有人可能会说这打破了MVVM的精神,但在某些时候你必须务实并转向更有趣的问题。
答案 3 :(得分:0)
以下是我为菜单项制作ViewModel的方法:AbstractMenuItem。特别注意Icon区域:
#region " Icon "
/// <summary>
/// Optional icon that can be displayed in the menu item.
/// </summary>
public object Icon
{
get
{
if (IconFull != null)
{
System.Windows.Controls.Image img = new System.Windows.Controls.Image();
if (EnableCondition.Condition)
{
img.Source = IconFull;
}
else
{
img.Source = IconGray;
}
return img;
}
else
{
return null;
}
}
}
private BitmapSource IconFull
{
get
{
return m_IconFull;
}
set
{
if (m_IconFull != value)
{
m_IconFull = value;
if (m_IconFull != null)
{
IconGray = ConvertFullToGray(m_IconFull);
}
else
{
IconGray = null;
}
NotifyPropertyChanged(m_IconArgs);
}
}
}
private BitmapSource m_IconFull = null;
static readonly PropertyChangedEventArgs m_IconArgs =
NotifyPropertyChangedHelper.CreateArgs<AbstractMenuItem>(o => o.Icon);
private BitmapSource IconGray { get; set; }
private BitmapSource ConvertFullToGray(BitmapSource full)
{
FormatConvertedBitmap gray = new FormatConvertedBitmap();
gray.BeginInit();
gray.Source = full;
gray.DestinationFormat = PixelFormats.Gray32Float;
gray.EndInit();
return gray;
}
/// <summary>
/// This is a helper function so you can assign the Icon directly
/// from a Bitmap, such as one from a resources file.
/// </summary>
/// <param name="value"></param>
protected void SetIconFromBitmap(System.Drawing.Bitmap value)
{
BitmapSource b = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
value.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
IconFull = b;
}
#endregion
您只是派生自此类,并在构造函数中调用SetIconFromBitmap并从resx文件传入图片。
以下是我如何绑定Workbench Window中的IMenuItem:
<Menu DockPanel.Dock="Top" ItemsSource="{Binding Path=(local:Workbench.MainMenu)}">
<Menu.ItemContainerStyle>
<Style>
<Setter Property="MenuItem.Header" Value="{Binding Path=(contracts:IMenuItem.Header)}"/>
<Setter Property="MenuItem.ItemsSource" Value="{Binding Path=(contracts:IMenuItem.Items)}"/>
<Setter Property="MenuItem.Icon" Value="{Binding Path=(contracts:IMenuItem.Icon)}"/>
<Setter Property="MenuItem.IsCheckable" Value="{Binding Path=(contracts:IMenuItem.IsCheckable)}"/>
<Setter Property="MenuItem.IsChecked" Value="{Binding Path=(contracts:IMenuItem.IsChecked)}"/>
<Setter Property="MenuItem.Command" Value="{Binding}"/>
<Setter Property="MenuItem.Visibility" Value="{Binding Path=(contracts:IControl.Visible),
Converter={StaticResource BooleanToVisibilityConverter}}"/>
<Setter Property="MenuItem.ToolTip" Value="{Binding Path=(contracts:IControl.ToolTip)}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=(contracts:IMenuItem.IsSeparator)}" Value="true">
<Setter Property="MenuItem.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type MenuItem}">
<Separator Style="{DynamicResource {x:Static MenuItem.SeparatorStyleKey}}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Menu.ItemContainerStyle>
</Menu>
答案 4 :(得分:0)
对于后人:我已经想出了这个:
<Menu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Icon" Value="{Binding IconUrl, Converter={ns:UrlToImageConverter Width=16, Height=16}}"/>
</Style>
</Menu.ItemContainerStyle>
转换器是MarkupExtension
和IValueConverter
的组合,因此您可以将其指定为内联,而无需将其设置为静态资源。
它使用System.Windows.Media.ImageSourceConverter
将uri转换为ImageSource
,然后使用该来源创建Image
控件。
作为奖励,它使用提供给serviceProvider
的{{1}}参数,因此它可以解析相对图像网址,因为WPF会这样做。
ProvideValue