コードでのWPF画像ソースの設定


325

コードでWPF画像のソースを設定しようとしています。画像はリソースとしてプロジェクトに埋め込まれます。例を見ると、以下のコードが思いついた。何らかの理由で機能しません-画像が表示されません。

デバッグすると、ストリームに画像データが含まれていることがわかります。何が問題なのですか?

Assembly asm = Assembly.GetExecutingAssembly();
Stream iconStream = asm.GetManifestResourceStream("SomeImage.png");
PngBitmapDecoder iconDecoder = new PngBitmapDecoder(iconStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
ImageSource iconSource = iconDecoder.Frames[0];
_icon.Source = iconSource;

アイコンは次のように定義されています。 <Image x:Name="_icon" Width="16" Height="16" />


イメージがローカルドライブにある<Image Source="some_fully_qualified_path">場合、XAMLで失敗することはありません。
Laurie Stearn 2017

@LaurieStearn要点は、パスがわからないため、パスを特定するためにコードが必要であることです。Windows GUIプログラミングの初心者として、私はWinFormsがこのXAMLのがらくたより魅力的だと認めざるを得ません。
Alex Jansen

回答:


416

あなたと同じ問題があり、いくつかの読書をした後、私はソリューション- パックURIを発見しました。

私はコードで次のことを行いました:

Image finalImage = new Image();
finalImage.Width = 80;
...
BitmapImage logo = new BitmapImage();
logo.BeginInit();
logo.UriSource = new Uri("pack://application:,,,/AssemblyName;component/Resources/logo.png");
logo.EndInit();
...
finalImage.Source = logo;

または、別のBitmapImageコンストラクターを使用して短くします。

finalImage.Source = new BitmapImage(
    new Uri("pack://application:,,,/AssemblyName;component/Resources/logo.png"));

URIは部分に分かれています。

  • 権限: application:///
  • パス:参照されるアセンブリにコンパイルされるリソースファイルの名前。パスは次の形式に準拠している必要があります。AssemblyShortName[;Version][;PublicKey];component/Path

    • AssemblyShortName:参照されるアセンブリの短い名前。
    • ; Version(オプション):リソースファイルを含む参照アセンブリのバージョン。これは、同じ短縮名を持つ2つ以上の参照アセンブリがロードされるときに使用されます。
    • ; PublicKey [オプション]:参照されるアセンブリの署名に使用された公開キー。これは、同じ短縮名を持つ2つ以上の参照アセンブリがロードされるときに使用されます。
    • ; component:参照されるアセンブリがローカルアセンブリから参照されることを指定します。
    • / Path:参照されるアセンブリのプロジェクトフォルダーのルートを基準にした、パスを含むリソースファイルの名前。

後の3つのスラッシュapplication:はコンマで置き換える必要があります。

注:パックURIの権限コンポーネントは、パッケージを指す埋め込みURIであり、RFC 2396に準拠する必要があります。さらに、「/」文字は「、」文字、および「%」などの予約文字に置き換える必要がありますそして「?」エスケープする必要があります。詳細については、OPCを参照してください。

そしてもちろん、イメージのビルドアクションを必ずに設定してくださいResource


はい、これは私がいくつかの試行錯誤の後に自分で見つけたソリューションでした。徹底した説明ありがとうございます。回答可!
トルビョルン

...これはかかわらず必要とされた理由を私は知らない、そしてなぜ他の答えは私のために動作しませんでした
Torbjørn

これに関する他の回答と他の質問も私にとってはうまくいきませんでした。これは完璧に動作します。ありがとう。
トーマス株

9
わかりましたが、XAMLパーサーが単純なパス文字列をImageSourceに変換するために使用するメソッドまたはクラスはありませんか?それだけでは使えないのでしょうか?
Qwertie

1
このスニペットが他の投稿にコピーされることがよくあります。通常、人々はBitmapImage(Uri)コンストラクターの存在を無視します。これにより、BeginInitおよびEndInitを呼び出す必要がなくなります。ここに追加しました。
クレメンス

175
var uriSource = new Uri(@"/WpfApplication1;component/Images/Untitled.png", UriKind.Relative);
foo.Source = new BitmapImage(uriSource);

これにより、「WpfApplication1」というアセンブリの「ビルドアクション」が「リソース」に設定された「Images」というフォルダーに「Untitled.png」というイメージが読み込まれます。


16
それをありがとう。私をwpfへのnoobとして起動した1つの問題は、これが機能するために、イメージをリソースとしてマークする必要があります。
si618 2009年

4
私はジャレッドハーレーのソリューションを試してみました、それが働いていたので、このソリューションは...私に例外を与えた
Sangram Nandkhile

2
最も重要なのは "UriKind.RelativeOrAbsolute"です-他の例は常に例外をスローしました
Sven

9
var uriSource = new Uri("Images/Untitled.png", UriKind.Relative);十分です
Hamzeh Soboh 2013

...そしてはるかに簡単です。ありがとうHamzeh
pStan

74

これは少しコードが少なく、1行で実行できます。

string packUri = "pack://application:,,,/AssemblyName;component/Images/icon.png";
_image.Source = new ImageSourceConverter().ConvertFromString(packUri) as ImageSource;

8
これは間違いなく最良の答えであり、.NET独自の実装を利用しています
joshcomley 2014

image.icon.pngの高さと幅を設定する必要がある場合はどうなりますか?_image.heightと_image.widthを使用することで、実際の画像ではなく画像ウィンドウを設定するためです。
secretgenes 2016

41

非常に簡単:

メニュー項目の画像を動的に設定するには、以下のみを実行します。

MyMenuItem.ImageSource = 
    new BitmapImage(new Uri("Resource/icon.ico",UriKind.Relative));

...「icon.ico」はどこにでも配置でき(現在は「Resources」ディレクトリにあります)、Resourceとしてリンクする必要があります...


2
短い=良い。@ "/ folder / image.png"に設定する必要がありましたが、その後はうまくいきました。ありがとう!
gjvdkamp

3
画像ソースを割り当てると、空白が表示されるだけです:(
HaloMediaz

@HaloMediazパスが間違っている可能性があります.... egリソースがありますが、それを記述できますリソース
Rouzbeh Zarandi

これは私にとってはうまくいき、他の答えの絶対URIよりもはるかに簡単です。
Psiloc

16

これを1行に減らすこともできます。これは、メインウィンドウのアイコンを設定するために使用したコードです。これは、.icoファイルがコンテンツとしてマークされ、出力ディレクトリにコピーされていることを前提としています。

 this.Icon = new BitmapImage(new Uri("Icon.ico", UriKind.Relative));

16

最も簡単な方法:

var uriSource = new Uri("image path here");
image1.Source = new BitmapImage(uriSource);

15

やってみました:

Assembly asm = Assembly.GetExecutingAssembly();
Stream iconStream = asm.GetManifestResourceStream("SomeImage.png");
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = iconStream;
bitmap.EndInit();
_icon.Source = bitmap;

13

これが私のやり方です:

internal static class ResourceAccessor
{
    public static Uri Get(string resourcePath)
    {
        var uri = string.Format(
            "pack://application:,,,/{0};component/{1}"
            , Assembly.GetExecutingAssembly().GetName().Name
            , resourcePath
        );

        return new Uri(uri);
    }
}

使用法:

new BitmapImage(ResourceAccessor.Get("Images/1.png"))

8

以下は、イメージパスを動的に設定する例です(リソースとしてビルドするのではなく、ディスク上のどこかにあるイメージ)。

if (File.Exists(imagePath))
{
    // Create image element to set as icon on the menu element
    Image icon = new Image();
    BitmapImage bmImage = new BitmapImage();
    bmImage.BeginInit();
    bmImage.UriSource = new Uri(imagePath, UriKind.Absolute);
    bmImage.EndInit();
    icon.Source = bmImage;
    icon.MaxWidth = 25;
    item.Icon = icon;
}

アイコンの考察...

最初に考えたのは、Iconプロパティには画像のみを含めることができると考えるでしょう。ただし、実際には何でも含めることができます。プログラムでImageプロパティを画像へのパスを含む文字列に直接設定しようとしたときに、これを偶然発見しました。その結果、画像は表示されず、パスの実際のテキストが表示されました。

これにより、アイコンの画像を作成する代わりに、単純な「アイコン」を表示する代わりに、シンボルフォントを使用したテキストを使用するという代替案が生まれます。次の例では、「floppydisk」シンボルを含むWingdingsフォントを使用しています。このシンボルは実際には<XAMLで特別な意味を持つ文字であるため、&lt;代わりにエンコードされたバージョンを使用する必要があります。これは夢のように機能します。以下は、フロッピーディスクシンボルをメニュー項目のアイコンとして示しています。

<MenuItem Name="mnuFileSave" Header="Save" Command="ApplicationCommands.Save">
  <MenuItem.Icon>
    <Label VerticalAlignment="Center" HorizontalAlignment="Center" FontFamily="Wingdings">&lt;</Label>
  </MenuItem.Icon>
</MenuItem>

質問:「イメージはプロジェクトのリソースとして埋め込まれています」、回答:「リソースとしてビルドするのではなく、ディスク上のどこかにある[イメージの例]を次に示します」。

7

画像がResourceDictionaryに保存されている場合は、1行のコードで実行できます。

MyImage.Source = MyImage.FindResource("MyImageKeyDictionary") as ImageSource;

6

より簡単な方法もあります。画像がXAMLのリソースとして読み込まれ、問題のコードがそのXAMLコンテンツの分離コードである場合:

Uri iconUri = new Uri("pack://application:,,,/ImageNAme.ico", UriKind.RelativeOrAbsolute);
NotifyIcon.Icon = BitmapFrame.Create(iconUri);

4

フレームをVisualBrushに配置します。

VisualBrush brush = new VisualBrush { TileMode = TileMode.None };

brush.Visual = frame;

brush.AlignmentX = AlignmentX.Center;
brush.AlignmentY = AlignmentY.Center;
brush.Stretch = Stretch.Uniform;

VisualBrushをGeometryDrawingに配置する

GeometryDrawing drawing = new GeometryDrawing();

drawing.Brush = brush;

// Brush this in 1, 1 ratio
RectangleGeometry rect = new RectangleGeometry { Rect = new Rect(0, 0, 1, 1) };
drawing.Geometry = rect;

次に、GeometryDrawingをDrawingImageに配置します。

new DrawingImage(drawing);

これを画像のソースに配置してください。

あなたはそれをはるかに簡単にすることができます:

<Image>
    <Image.Source>
        <BitmapImage UriSource="/yourassembly;component/YourImage.PNG"></BitmapImage>
    </Image.Source>
</Image>

そしてコードでは:

BitmapImage image = new BitmapImage { UriSource="/yourassembly;component/YourImage.PNG" };

笑!あなたが最初にそれを困難にすることができるときなぜ簡単にそれを作る:)私も受け入れる前に、私はあなたの簡単な解決策を試してみましょう...
Torbjørn

実際、これは私にはまったく役に立ちませんでした。たぶん私は愚かだ:( DOは(ペットプロジェクト)今より密接に見て時間を持っていないだろう、私はそれに戻って得るときのためのより多くの答えのように:)。
Torbjørn

3

より簡単な方法もあります。画像がXAMLのリソースとして読み込まれ、問題のコードがそのXAMLの分離コードである場合:

XAMLファイルのリソースディクショナリは次のとおりです。重要なのは、「PosterBrush」というキーを持つImageBrushだけです。残りのコードは、コンテキストを表示するだけです。

<UserControl.Resources>
        <ResourceDictionary>
            <ImageBrush x:Key="PosterBrush" ImageSource="..\Resources\Images\EmptyPoster.jpg" Stretch="UniformToFill"/>

        </ResourceDictionary>
    </UserControl.Resources>

今、コードビハインドでは、これを行うことができます

ImageBrush posterBrush = (ImageBrush)Resources["PosterBrush"];

2

リソースアイコンと画像に埋め込まれた画像を読み込む方法(Arcturusの修正バージョン):

画像付きのボタンを追加するとします。あなたは何をするべきか?

  1. プロジェクトフォルダアイコンに追加し、ここに画像ClickMe.pngを配置します
  2. 「ClickMe.png」のプロパティで、「BuildAction」を「Resource」に設定します
  3. コンパイルされたアセンブリ名が 'Company.ProductAssembly.dll'であるとします。
  4. XAMLに画像を読み込む時が来ました

    <Button Width="200" Height="70">
      <Button.Content>
        <StackPanel>
          <Image Width="20" Height="20">
            <Image.Source>
              <BitmapImage UriSource="/Company.ProductAssembly;component/Icons/ClickMe.png"></BitmapImage>
              </Image.Source>
          </Image>
          <TextBlock HorizontalAlignment="Center">Click me!</TextBlock>
        </StackPanel>
      </Button.Content>
    </Button>

できました。


2

私はWPFの初心者ですが、.NETはそうではありません。

.NET 3.5(Visual Studio 2010)の「WPFカスタムコントロールライブラリプロジェクト」にPNGファイルを追加し、画像継承コントロールの背景として設定するために5時間を費やしました。

URIに関連するものは何も機能しませんでした。IntelliSenseを介して、リソースファイルからURIを取得する方法がないのはなぜでしょうか。

Properties.Resources.ResourceManager.GetURI("my_image");

多くのURIを試し、ResourceManagerとAssemblyのGetManifestメソッドを試してみましたが、すべて例外またはNULL値がありました。

ここに私のために働いたコードを植えます:

// Convert the image in resources to a Stream
Stream ms = new MemoryStream()
Properties.Resources.MyImage.Save(ms, ImageFormat.Png);

// Create a BitmapImage with the stream.
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = ms;
bitmap.EndInit();

// Set as source
Source = bitmap;

3
問題は、WPFがリソースをresxファイルに配置する従来のアプローチを「好きではない」ということです。代わりに、イメージをプロジェクトに直接追加し、そのビルドアクションプロパティをリソースに設定することになっています。2つのアプローチの違い(物理ファイル形式)が何であるかわかりません。
Qwertie

1
ビルドアクションがコンテンツであることを確認
ジェリーニクソン、

1

すでにストリームがあり、形式がわかっている場合は、次のようなものを使用できます。

static ImageSource PngStreamToImageSource (Stream pngStream) {
    var decoder = new PngBitmapDecoder(pngStream,
        BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
    return decoder.Frames[0];
}

1

あなたは少しだけ逃した。

アセンブリから埋め込みリソースを取得するには、ここで述べたように、ファイル名でアセンブリ名を指定する必要があります。

Assembly asm = Assembly.GetExecutingAssembly();
Stream iconStream = asm.GetManifestResourceStream(asm.GetName().Name + "." + "Desert.jpg");
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = iconStream;
bitmap.EndInit();
image1.Source = bitmap;

BeginInit()はWPFに存在しないようです。
Myosotis 2016年

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.