2008-12-07 5 views
356

Je viens d'un environnement principalement web et un peu Windows Forms. Pour un nouveau projet, nous utiliserons WPF. L'application WPF aura besoin de 10 à 20 petites icônes et images à des fins d'illustration. Je pense à stocker ces éléments dans l'assemblage en tant que ressources intégrées. Est-ce la bonne façon d'y aller?Ressources image WPF

Comment puis-je spécifier en XAML qu'un contrôle Image doit charger l'image à partir d'une ressource incorporée?

Répondre

421

Si vous souhaitez utiliser l'image à plusieurs endroits, il est préférable de charger les données d'image une seule fois en mémoire, puis de les partager entre tous les éléments Image.

Pour ce faire, créez un BitmapSource comme ressource quelque part:

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

Ensuite, dans votre code, utilisez quelque chose comme:

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

Dans mon cas, je trouve que je devais définir le fichier Image.png pour avoir une action de construction de Resource plutôt que seulement Content. Cela provoque le transport de l'image dans votre assembly compilé.

+5

Serait-il possible de le faire dynamiquement? Si j'ai un nombre différent d'images que je voudrais charger au démarrage, pourrais-je créer un BitmapSource par image et me référer à eux de la même manière que ci-dessus? –

+2

@Becky - Oui, bien que si vous vouliez vous y référer dans Xaml, vous pourriez avoir besoin d'utiliser l'extension de balisage 'DynamicResource' au lieu de' StaticResource', en supposant que vous connaissiez les clés au moment de la compilation. Dans WPF, vous pouvez créer des dictionnaires de ressources au moment de l'exécution. En fait, c'est ce qui arrive quand vous chargez un document Xaml, c'est juste que vous ne voyez pas le C# équivalent. –

+0

Merci pour la réponse :) Je vais me référer à eux via FindResource, mais je pense que cela peut sauver une quantité ridicule de traitement dans mon application maintenant donc merci :) –

34

oui c'est la bonne façon. Vous pouvez utiliser l'image dans le fichier de ressources juste en utilisant le chemin:

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

Vous devez définir l'action de construction du fichier d'image « ressources »

+1

Merci pour cela. Existe-t-il un moyen de faire quelque chose de similaire avec ImageSource, en chargeant essentiellement l'image une fois dans un dictionnaire de ressources. Je crains que cette approche charge les données d'image plusieurs fois en mémoire. –

+2

Ce sera un désordre lorsque vous avez besoin de refactoriser votre code. Vous devrez modifier manuellement toutes les références d'image si votre document xaml arrive à changer d'espace de noms. La méthode décrite par Drew Noakes est beaucoup plus lisse et maintable. –

2

Si vous utilisez un mélange, pour le rendre extra facile et ne pas avoir de problème pour obtenir le bon chemin pour l'attribut Source, il suffit de glisser et déposer l'image du panneau Projet sur le concepteur.

150

Je trouve être la meilleure pratique de l'utilisation d'images, vidéo, etc est:

  • Changer vos fichiers "action Build" à "Contenu". Assurez-vous de vérifier Copier pour construire le répertoire
    • trouvé dans le menu "clic droit" à la fenêtre Explorateur de solutions
  • Image Source dans le format suivant:
    • «/« YourAssemblyName »; composant /« YourPath »/ « YourImage..png »"

Exemple

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

Avantages:

  • fichiers ne sont pas intégrés dans l'ensemble
    • Le gestionnaire des ressources soulèvera un certain débordement de mémoire pro blèmes avec trop de ressources (au moment de la construction)
  • Peut-on appeler entre les assemblées
+28

Cette même approche fonctionne si vous intégrez la ressource dans l'assembly, mais vous devez définir le " Construire l'action "à" ressource ". –

+4

Fonctionne, merci. Une note pour les autres: "component" est requis "tel quel", "Images" est un chemin relatif de png dans le projet. C'est à dire. l'image qui est placée dans la racine sera "" – Badiboy

+3

Un exemple de comment faire ceci en C# serait bien. (Ce n'est pas un URI valide donc il ne peut pas être utilisé lors de la construction d'un bitmapImage.) – Vaccano

41

Certaines personnes demandent à faire cela dans le code et ne pas obtenir un rép er. Après avoir passé de nombreuses heures à chercher j'ai trouvé une méthode très simple, je n'ai trouvé aucun exemple et donc je partage le mien ici qui fonctionne avec des images. (Le mien était un .gif)

Résumé:

Il retourne un BitmapFrame qui ImageSource "destinations" semblent aimer.

Utilisation:

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

Méthode:

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

Apprentissages:

De mes expériences la chaîne pack n'est pas le problème, vérifiez vos flux et surtout si la lecture la première fois a mis le pointeur à la fin du fichier et vous devez le remettre à zéro avant de relire.

J'espère que cela vous évite les nombreuses heures que je souhaite que cette pièce ait pour moi!

4
  1. Visual Studio 2010 Professionnel SP1.
  2. .NET Framework 4 Client Profile.
  3. Image PNG ajoutée comme ressource sur les propriétés du projet.
  4. Nouveau fichier dans le dossier Ressources créé automatiquement.
  5. Créer une action définie sur une ressource.

Cela a fonctionné pour moi:

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

Dans le code pour charger une ressource dans l'ensemble de executiong où mon image Freq.png était dans le dossier Icons et défini comme Resource:

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

I a également fait une fonction si quelqu'un peut l'utiliser:

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

Utilisation (hypothèse que vous mettez la fonction dans une classe ResourceHelper):

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

Remarque: voir MSDN Pack URIs in WPF:
pack://application:,,,/ReferencedAssembly;component/Subfolder/ResourceFile.xaml

+0

new Uri throws Invalid URI: port non valide spécifié. – Steve

+0

Avez-vous l'uri offensant? –

+0

même uri que la vôtre sauf que la mienne était en cours d'exécution dans un WPF hébergé Winform. Et le schéma "pack" n'était pas encore enregistré quand j'ai appelé le nouvel Uri. – Steve

-4

Cela a fonctionné

et les images à définir est des ressources dans les propriétés

var bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(MyProject.Properties.Resources.myImage.GetHbitmap(), 
             IntPtr.Zero, 
             Int32Rect.Empty, 
             BitmapSizeOptions.FromEmptyOptions()); 
    MyButton.Background = new ImageBrush(bitmapSource); 
img_username.Source = bitmapSource; 
+0

Aucune infraction mais cela sent comme une mauvaise pratique. – ShloEmi