WPF-Bildressourcen

408

Ich komme hauptsächlich aus dem Internet und ein bisschen Windows Forms-Hintergrund. Für ein neues Projekt werden wir WPF verwenden. Die WPF-Anwendung benötigt zur Veranschaulichung 10 bis 20 kleine Symbole und Bilder. Ich denke darüber nach, diese in der Assembly als eingebettete Ressourcen zu speichern. Ist das der richtige Weg?

Wie gebe ich in XAML an, dass ein Image-Steuerelement das Image von einer eingebetteten Ressource laden soll?

driis
quelle

Antworten:

473

Wenn Sie das Bild an mehreren Stellen verwenden, sollten Sie die Bilddaten nur einmal in den Speicher laden und dann für alle ImageElemente freigeben.

Erstellen Sie dazu BitmapSource irgendwo eine Ressource:

<BitmapImage x:Key="MyImageSource" UriSource="../Media/Image.png" />

Verwenden Sie dann in Ihrem Code Folgendes:

<Image Source="{StaticResource MyImageSource}" />

In meinem Fall stellte ich fest, dass ich die Image.pngDatei so einstellen musste, dass sie nicht nur eine Build-Aktion Resourceausführt Content. Dadurch wird das Image in Ihrer kompilierten Assembly übertragen.

Drew Noakes
quelle
6
Wäre es möglich, dies dynamisch zu tun? Wenn ich eine unterschiedliche Anzahl von Bildern habe, die ich beim Start laden möchte, kann ich dann eine BitmapSource pro Bild erstellen und auf dieselbe Weise wie oben verweisen?
Becky Franklin
2
@Becky - Ja, Sie könnten, aber wenn Sie in Xaml auf sie verweisen möchten, müssen Sie möglicherweise DynamicResourcestattdessen die Markup-Erweiterung verwenden StaticResource, vorausgesetzt, Sie kennen die Schlüssel zur Kompilierungszeit. In WPF können Sie zur Laufzeit Ressourcenwörterbücher erstellen. Genau das passiert, wenn Sie ein Xaml-Dokument laden. Es ist nur so, dass Sie nicht das entsprechende C # sehen.
Drew Noakes
9
Etwas, das ich getroffen habe: Wenn Sie Ihre Bildressource zu einem Ressourcenwörterbuch hinzufügen, vergessen Sie nicht, für Ihre Komponente auf dieses Bildwörterbuch in der XAML zu verweisen. So etwas wie: <UserControl.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source = "Dictionary1.xaml" /> </ResourceDictionary.MergedDictionaries> </ ResourceDictionary> </UserControl.Resources>
Dan Mitchell
4
Ich in der Regel hinzufügen , Width="{Binding Source.PixelWidth, RelativeSource={RelativeSource Self}}" um die Image, wie sonst oft ich Bilder zu sehen grotesk immer aus irgendeinem Grunde skaliert (wie 16x16 Icons etwas gedehnt , dass sieht aus wie 200x200 Pixel).
ODER Mapper
5
Ich habe festgestellt, dass, wenn das BitmapImage im Ressourcenverzeichnis einer referenzierten Assembly deklariert ist, die UriSource eine packURI sein muss, damit dies funktioniert. Andernfalls werden Sie feststellen, dass Sie das Bild in Ihrem xaml-Editor in VS sehen können, aber beim Debuggen kein Bild. Pack URIS: msdn.microsoft.com/en-au/library/aa970069(v=vs.100).aspx
Programmierung fehlgeschlagen
174

Ich habe festgestellt, dass die beste Vorgehensweise bei der Verwendung von Bildern, Videos usw. ist:

  • Ändern Sie Ihre Dateien "Aktion erstellen " in "Inhalt" . Stellen Sie sicher, dass das Kontrollkästchen In Verzeichnis erstellen kopiert ist .
    • Gefunden im Menü "Rechtsklick" im Fenster "Projektmappen-Explorer".
  • Bildquelle im folgenden Format:
    • "/ « YourAssemblyName » ; Komponente /« YourPath »/ « YourImage.png » "

Beispiel

<Image Source="/WPFApplication;component/Images/Start.png" />

Leistungen:

  • Dateien werden nicht in die Assembly eingebettet.
    • Der Ressourcenmanager führt bei zu vielen Ressourcen (zum Zeitpunkt der Erstellung) zu Problemen mit dem Speicherüberlauf.
  • Kann zwischen Baugruppen aufgerufen werden.
Nuno Rodrigues
quelle
36
Der gleiche Ansatz funktioniert, wenn Sie die Ressource in die Assembly einbetten, aber die "Build-Aktion" auf "Ressource" setzen müssen.
Ashley Davis
5
Funktioniert, danke. Ein Hinweis für andere: "Komponente" ist erforderlich "wie", "Bilder" ist ein relativer Pfad von PNG im Projekt. Das Bild, das im Stammverzeichnis platziert wird, ist "<Image Source =" / WPFApplication; component / Start.png "/>"
Badiboy
3
Ein Beispiel, wie dies in C # gemacht wird, wäre schön. (Das ist kein gültiger URI, daher kann er beim Erstellen eines BitmapImage nicht verwendet werden.)
Vaccano
5
Wie machen Sie das, wenn die Datei auf Embedded Resource eingestellt ist? Das scheint nicht zu funktionieren. Und ich möchte das Bild nicht zweimal in mein Projekt aufnehmen. (Ich benutze es bereits als eingebettete Ressource.)
BrainSlugs83
2
Wo und wie kommt "Komponente" in den Pfad. Ist das Teil einer Spezifikation?
Triynko
46

Einige Leute fragen, ob sie dies im Code tun und keine Antwort erhalten.

Nachdem ich viele Stunden lang gesucht hatte, fand ich eine sehr einfache Methode, ich fand kein Beispiel und teile meine hier, die mit Bildern funktioniert. (meins war ein .gif)

Zusammenfassung:

Es gibt einen BitmapFrame zurück, den ImageSource- "Ziele" zu mögen scheinen.

Verwenden:

doGetImageSourceFromResource ("[YourAssemblyNameHere]", "[YourResourceNameHere]");

Methode:

static internal ImageSource doGetImageSourceFromResource(string psAssemblyName, string psResourceName)
{
    Uri oUri = new Uri("pack://application:,,,/" +psAssemblyName +";component/" +psResourceName, UriKind.RelativeOrAbsolute);
    return BitmapFrame.Create(oUri);
}

Erkenntnisse:

Nach meinen Erfahrungen ist die Pack-Zeichenfolge nicht das Problem. Überprüfen Sie Ihre Streams und insbesondere, wenn Sie sie zum ersten Mal lesen, haben Sie den Zeiger auf das Ende der Datei gesetzt und müssen sie vor dem erneuten Lesen auf Null zurücksetzen.

Ich hoffe, das erspart Ihnen die vielen Stunden, die ich mir für dieses Stück gewünscht habe!

Craig
quelle
44

Im Code zum Laden einer Ressource in der ausführenden Assembly, in der sich mein Image Freq.pngim Ordner befand Iconsund wie folgt definiert ist Resource:

this.Icon = new BitmapImage(new Uri(@"pack://application:,,,/" 
    + Assembly.GetExecutingAssembly().GetName().Name 
    + ";component/" 
    + "Icons/Freq.png", UriKind.Absolute)); 

Ich habe auch eine Funktion gemacht:

/// <summary>
/// Load a resource WPF-BitmapImage (png, bmp, ...) from embedded resource defined as 'Resource' not as 'Embedded resource'.
/// </summary>
/// <param name="pathInApplication">Path without starting slash</param>
/// <param name="assembly">Usually 'Assembly.GetExecutingAssembly()'. If not mentionned, I will use the calling assembly</param>
/// <returns></returns>
public static BitmapImage LoadBitmapFromResource(string pathInApplication, Assembly assembly = null)
{
    if (assembly == null)
    {
        assembly = Assembly.GetCallingAssembly();
    }

    if (pathInApplication[0] == '/')
    {
        pathInApplication = pathInApplication.Substring(1);
    }
    return new BitmapImage(new Uri(@"pack://application:,,,/" + assembly.GetName().Name + ";component/" + pathInApplication, UriKind.Absolute)); 
}

Verwendung (Annahme, dass Sie die Funktion in eine ResourceHelper-Klasse einfügen):

this.Icon = ResourceHelper.LoadBitmapFromResource("Icons/Freq.png");

Hinweis : Siehe MSDN Pack-URIs in WPF :
pack://application:,,,/ReferencedAssembly;component/Subfolder/ResourceFile.xaml

Eric Ouellet
quelle
neuer Uri löst ungültigen URI aus: Ungültiger Port angegeben.
Steve
Hast du den beleidigenden Uri?
Eric Ouellet
1
Dieselbe Uri wie deine, außer dass meine in einer von Winform gehosteten WPF lief. Und das "Pack" -Schema wurde noch nicht registriert, als ich den neuen Uri anrief.
Steve
1
Ups ... es ist wahrscheinlich für Winform gehostete WPF retated. Es tut mir Leid. Ich werde nicht versuchen, das Problem zu beheben, da ich denke, dass es keine sehr häufige Verwendung ist. Viel Glück!
Eric Ouellet
In meinem Fall hat die Verwendung new Uri(@"pack://application:,,,/" + pathInApplication)auch den Trick getan.
Adam Calvet Bohl
40

Ja, das ist der richtige Weg.

Sie können das Bild in der Ressourcendatei nur über den Pfad verwenden:

<Image Source="..\Media\Image.png" />

Sie müssen die Erstellungsaktion der Bilddatei auf "Ressource" setzen.

ema
quelle
1
Danke dafür. Gibt es eine Möglichkeit, mit einer ImageSource etwas Ähnliches zu tun, indem das Bild im Wesentlichen einmal in ein Ressourcenwörterbuch geladen wird? Ich befürchte, dass dieser Ansatz die Bilddaten mehrmals in den Speicher lädt.
Drew Noakes
2
Dies ist ein Chaos, wenn Sie Ihren Code umgestalten müssen. Sie müssen alle Bildreferenzen manuell ändern, wenn Ihr xaml-Dokument den Namespace ändert. Die von Drew Noakes beschriebene Methode ist viel reibungsloser und wartbarer.
Kasper Holdum
14

Vollständige Beschreibung der Verwendung von Ressourcen: WPF-Anwendungsressourcen, Inhalte und Datendateien

Informationen zum Referenzieren finden Sie unter "Packen von URIs in WPF".

Kurz gesagt, es gibt sogar Mittel, um Ressourcen aus referenzierten / referenzierenden Assemblys zu referenzieren.

Techfan
quelle
Der Link scheint live und gut zu sein (obwohl dort steht "Diese Dokumentation ist archiviert und wird nicht gepflegt." ).
Peter Mortensen
5
  1. Visual Studio 2010 Professional SP1.
  2. .NET Framework 4-Clientprofil.
  3. PNG-Bild als Ressource für Projekteigenschaften hinzugefügt.
  4. Neue Datei im Ordner Ressourcen wird automatisch erstellt.
  5. Aktionssatz auf Ressource setzen.

Das hat bei mir funktioniert:

<BitmapImage x:Key="MyImageSource" UriSource="Resources/Image.png" />
JoanComasFdz
quelle
3

Wenn Sie verwenden Blend verwenden , ziehen Sie das Bild einfach aus dem Projektfenster auf den Designer , um es besonders einfach zu machen und keine Probleme zu haben, den richtigen Pfad für das Source- Attribut zu finden.

user42467
quelle
3

Ja, das ist der richtige Weg. Sie können Bilder in der Ressourcendatei mithilfe eines Pfads verwenden:

<StackPanel Orientation="Horizontal">
    <CheckBox  Content="{Binding Nname}" IsChecked="{Binding IsChecked}"/>
    <Image Source="E:\SWorking\SharePointSecurityApps\SharePointSecurityApps\SharePointSecurityApps.WPF\Images\sitepermission.png"/>
    <TextBlock Text="{Binding Path=Title}"></TextBlock>
</StackPanel>
Sanjay Ranavaya
quelle
-5

Die folgenden Arbeiten und die einzustellenden Bilder sind Ressourcen in den Eigenschaften:

    var bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(MyProject.Properties.Resources.myImage.GetHbitmap(),
                                      IntPtr.Zero,
                                      Int32Rect.Empty,
                                      BitmapSizeOptions.FromEmptyOptions());
    MyButton.Background = new ImageBrush(bitmapSource);
img_username.Source = bitmapSource;
Raghulan Gowthaman
quelle
5
Nichts für ungut, aber das riecht nach schlechter Praxis.
ShloEmi