5

MenuItemここでは、a をデータ オブジェクトにバインドする例に従っています。

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

私は何を間違っていますか?

4

5 に答える 5

9

Kent (もちろん) は正しい答えを持っています。しかし、System.Drawing.Bitmap (Windows フォーム) から System.Windows.Windows.Media.BitmapSource (WPF) に変換するコンバーターのコードを投稿することにしました。これは一般的な問題であるためです。 /質問。

これには、次の 3 つの手順が必要です。

  1. バインディングで画像コンバーターを使用します。
  2. コンバーターを作成します。
  3. リソースでコンバーターを宣言します。

バインディングで画像コンバーターを使用する方法は次のとおりです。

<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がここで以前のコンバーターの実装にリー​​クがあることを指摘していることに気付きました。上記のコンバーターコードを更新しました...リークしないようにします。

リークの原因の詳細については、この MSDNリンクの備考セクションを参照してください。

于 2010-04-21T16:42:10.057 に答える
5

WPF は、クラスImageSourceではなく s で動作します。System.Drawingにバインドする必要がありますImageSource。コンバーターを使用して を に変換するBitmapことImageSourceも、リソースを捨てて別の方法で行うこともできます。

于 2009-11-24T12:47:12.403 に答える
0

メニュー項目のViewModelを作成した方法は次のとおりです:AbstractMenuItem。アイコン領域に特に注意してください。

    #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ファイルから画像を渡します。

ワークベンチウィンドウでこれらの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>
于 2009-12-05T02:45:48.653 に答える