Comment Définir l'Image de Ressource URI à partir du Code-Behind
Je suis en train d'intégrer une image PNG dans une DLL et de le charger dans un Image
de contrôle comme un BitmapImage
. Cependant, WPF garde lancer une exception en disant que la ressource ne peut pas être trouvé.
Tout d'abord, un minimum de code de l'échantillon et les étapes pour reproduire le problème:
-
Créer un projet WPF nommé ImageResTest avec un vide de la fenêtre principale (vous pouvez définir l'espace de noms par défaut pour
ImageResTest
). Le fichier code-behind de la fenêtre principale devrait ressembler à ceci:using System; using System.Windows; using System.Windows.Controls; namespace ImageResTest { public partial class Window1 : Window { public Window1() { InitializeComponent(); var obj = new MyData.SomeStuff.MyClass(); this.Content = obj.Img; } } }
-
Créer une bibliothèque de classe nommé ImageResTestLib (vous pouvez définir l'espace de noms par défaut pour
ImageResTest
, comme ci-dessus, de sorte que ce qui a été abordé ici est dans le même espace de noms racine). - Ajouter des références à partir de ImageResTestLib à PresentationCore, PresentationFramework, Système.Xaml et WindowsBase.
- Ajouter une référence à partir de ImageResTest à ImageResTestLib.
- À l'intérieur de ImageResTestLib, ajouter la hiérarchie des dossiers
MyData/SomeStuff/Resources
. -
Dans le
SomeStuff
dossier, ajouter le fichier suivant MyClass.cs:using System; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; namespace ImageResTest.MyData.SomeStuff { public class MyClass { public MyClass() { img = new Image(); { var bmp = new BitmapImage(); bmp.BeginInit(); bmp.UriSource = new Uri(@"/ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png", UriKind.RelativeOrAbsolute); bmp.EndInit(); img.Source = bmp; img.Width = bmp.PixelWidth; } } private Image img; public Image Img { get { return img; } } } }
-
Dans le
Resources
dossier, ajouter un fichier PNG nomméImg.png
et de définir son action de construire à Ressources (comme l'a suggéré, par exemple, ici).
Jusqu'ici tout va bien - le lancement de cette application doit créer une fenêtre qui instancie MyClass
et récupère un Image
créé par MyClass
instance. Cette image doit avoir été rempli avec un BitmapImage
dont les données ont été chargées à partir du graphique inclus en tant que ressource.
Malheureusement, il semble y avoir quelque chose de mal avec l'URI de la ressource. Le documentation sur MSDN n'a pas aidé à ce jour.
J'ai essayé les variantes suivantes de la ressource Uri:
- La forme représentée dans l'exemple de code ci -
/AssemblyName;component/Path/Filename
a été proposé ici et ici, mais unDirectoryNotFoundException
est levée, disant qu'une partie du cheminC:\ImageResTestLib;component\MyData\SomeStuff\Resources\Img.png
n'a pas été trouvé. pack://application:,,,/MyData/SomeStuff/Resources/Img.png
a été suggéré ici, ici, ici et ici, mais jette unIOException
dire que la ressourcemydata/somestuff/resources/img.png
n'a pas pu être trouvé.pack://application:,,,/ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png
a également été suggéré ici, ainsi que ici, mais jette unFileNotFoundException
dire queImageResTestLib, Culture=neutral
ou une de ses dépendances n'a pas été trouvé.Resources/Img.png
(par rapport à partir du fichier de code) a été implicite ici et ici, mais jette unDirectoryNotFoundException
dire queC:\Users\myusername\Documents\Test\DOTNET\WPFTest\ImageResTest\bin\Debug\Resources\Img.png
n'a pas été trouvé.MyData/SomeStuff/Resources/Img.png
(par rapport au projet), et aussi implicite ici, se comporte de façon analogue à la précédente.
Comme aucun de ces travaux, j'ai essayé la solution de contournement suivante basée sur une ResourceDictionary
:
- Ajouter un WPF dictionnaire de ressources nommé MyClassResources.xaml dans le
SomeStuff
dossier. - Dans cette ressource dictioanry, ajouter un
BitmapImage
de ressources avec la cléimg
. -
Modifier le contenu de MyClass.cs comme ceci:
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; namespace ImageResTest.MyData.SomeStuff { public class MyClass { public MyClass() { ResourceDictionary dict = new ResourceDictionary(); dict.Source = new Uri("/ImgResTestLib;component/MyData/SomeStuff/MyClassResources.xaml", UriKind.RelativeOrAbsolute); img = new Image(); { var bmp = (BitmapImage)dict["img"]; img.Source = bmp; img.Width = bmp.PixelWidth; } } private Image img; public Image Img { get { return img; } } } }
Maintenant, le dictionnaire de ressources peuvent être chargés à partir de l'a indiqué URI (lors de la suppression du contenu de la ressource dictionnaire, le chargement terminé avec succès). Cependant, les images PNG sont toujours pas trouvé lors de l'utilisation d'un chemin comme /ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png
.
Ce que je fais mal et comment puis-je charger les ressources nécessaires (si possible, sans le dictionnaire de ressources)?
EDIT: plus d'informations:
- Je suis en utilisant une version allemande de Windows 7 x64
- .NET 4.0 Client est défini comme le framework cible
- Juste pour être sûr, j'ai essayé avec la construction et l'exécution de cette deux à partir de Visual Studio 2010 et SharpDevelop 4.3.3; les deux fois, résultant dans la même exception.
La stacktrace de la FileNotFoundException
je me suis basé sur Ianle code est comme suit:
System.Windows.Markup.XamlParseException: Zeilennummer "3" und Zeilenposition "2" von "Durch den Aufruf des Konstruktors für Typ "ImageResTest.Window1", der den angegebenen Bindungseinschränkungen entspricht, wurde eine Ausnahme ausgelöst.". ---> System.IO.FileNotFoundException: Die Datei oder Assembly "ImageResTestLib, Culture=neutral" oder eine Abhängigkeit davon wurde nicht gefunden. Das System kann die angegebene Datei nicht finden.
bei System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
bei System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
bei System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
bei System.Reflection.Assembly.Load(AssemblyName assemblyRef)
bei System.Windows.Navigation.BaseUriHelper.GetLoadedAssembly(String assemblyName, String assemblyVersion, String assemblyKey)
bei MS.Internal.AppModel.ResourceContainer.GetResourceManagerWrapper(Uri uri, String& partName, Boolean& isContentFile)
bei MS.Internal.AppModel.ResourceContainer.GetPartCore(Uri uri)
bei System.IO.Packaging.Package.GetPartHelper(Uri partUri)
bei System.IO.Packaging.Package.GetPart(Uri partUri)
bei System.IO.Packaging.PackWebResponse.CachedResponse.GetResponseStream()
bei System.IO.Packaging.PackWebResponse.GetResponseStream()
bei System.IO.Packaging.PackWebResponse.get_ContentType()
bei System.Windows.Media.Imaging.BitmapDecoder.SetupDecoderFromUriOrStream(Uri uri, Stream stream, BitmapCacheOption cacheOption, Guid& clsId, Boolean& isOriginalWritable, Stream& uriStream, UnmanagedMemoryStream& unmanagedMemoryStream, SafeFileHandle& safeFilehandle)
bei System.Windows.Media.Imaging.BitmapDecoder.CreateFromUriOrStream(Uri baseUri, Uri uri, Stream stream, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption, RequestCachePolicy uriCachePolicy, Boolean insertInDecoderCache)
bei System.Windows.Media.Imaging.BitmapImage.FinalizeCreation()
bei System.Windows.Media.Imaging.BitmapImage.EndInit()
bei ImageResTest.MyData.SomeStuff.MyClass..ctor(Uri baseUri) in C:\Users\username\Documents\Test\DOTNET\WPFTest\ImgResTestLib\MyData\SomeStuff\MyClass.cs:Zeile 36.
bei ImageResTest.Window1..ctor() in c:\Users\username\Documents\Test\DOTNET\WPFTest\ImageResTest\Window1.xaml.cs:Zeile 17.
--- End of inner exception stack trace ---
bei System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)
bei System.Windows.Markup.WpfXamlLoader.LoadBaml(XamlReader xamlReader, Boolean skipJournaledProperties, Object rootObject, XamlAccessLevel accessLevel, Uri baseUri)
bei System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext parserContext, Object parent, Boolean closeStream)
bei System.Windows.Application.LoadBamlStreamWithSyncInfo(Stream stream, ParserContext pc)
bei System.Windows.Application.LoadComponent(Uri resourceLocator, Boolean bSkipJournaledProperties)
bei System.Windows.Application.DoStartup()
bei System.Windows.Application.<.ctor>b__1(Object unused)
bei System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
bei MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
bei System.Windows.Threading.DispatcherOperation.InvokeImpl()
bei System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
bei System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
bei System.Windows.Threading.DispatcherOperation.Invoke()
bei System.Windows.Threading.Dispatcher.ProcessQueue()
bei System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
bei MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
bei MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
bei System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
bei MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
bei System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
bei MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
bei MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
bei System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
bei System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
bei System.Windows.Threading.Dispatcher.Run()
bei System.Windows.Application.RunDispatcher(Object ignore)
bei System.Windows.Application.RunInternal(Window window)
bei System.Windows.Application.Run(Window window)
bei System.Windows.Application.Run()
bei ImageResTest.App.Main() in c:\Users\username\Documents\Test\DOTNET\WPFTest\ImageResTest\obj\Debug\App.g.cs:Zeile 0.
EDIT2:
Ajoutant
Debug.WriteLine(typeof(MyData.SomeStuff.MyClass).Assembly.GetName().FullName);
le constructeur de la fenêtre principale de résultats dans la sortie suivante:
ImgResTestLib, Version=1.0.5123.16826, Culture=neutral, PublicKeyToken=null
L'appel à
Debug.WriteLine(BaseUriHelper.GetBaseUri(this).ToString());
imprime le suivant:
pack://application:,,,/ImageResTest;component/window1.xaml
EDIT3:
Alors que l'on a accepté de répondre résout le problème décrit par la présente question, la vraie raison de pourquoi je ne pouvais pas voir mon graphique dans mon projet actuel est tout à fait quelque chose de différent:
Tout ni par rapport à 2010, ni SharpDevelop donner tout indication de cela, les ressources marqué comme Ressources fait un nom logique (dans mon cas, ils ont conservé de quand j'avais provisoirement de l'action de construire à EmbeddedResource et changé le nom logique). Le nom logique apparaît toujours dans un <LogicalName>
élément dans le fichier MSBuild et de ce que je peux voir dans ILSpy, que est ce qui est réellement utilisé comme le nom de la ressource dans l'assembly compilé.
Correcte (de travail) et de la ressource URI de la ressource avec un nom logique semble être
/MyAssembly;component/LogicalResourceName
(remplaçant ainsi le chemin d'accès au répertoire de la ressource, comme d'habitude pour EmbeddedResource ressources)
Alors qu'il n'est pas possible de modifier le nom logique de VS ou de SharpDevelop alors que l'action de construire est fixé à Ressources, en supprimant les ressources et re-ajout du fichier, puis le réglage de l'action de construire à Ressources, rendant le nom de fichier basé sur l'Uri de travailler de nouveau que le nom logique ne sera pas dans le fichier de projet. De même, le retrait de la <LogicalName>
élément manuellement à partir du fichier MSBuild devrait fonctionner.
MyClass
dans le ImageRestTestLib
composant, mais votre code source montre l'espace de ImageRestTest
, ce qui implique qu'il est dans la principale ImageRestTest
projet. Évidemment, il n'y a rien qui vous empêche d'utiliser des espaces de noms différents, mais je voulais vérifier dans le cas où il y a une erreur dans les instructions.Non, c'est volontaire, donc tout est ici dans le même espace de noms racine. Merci pour la remarque; j'ai ajouté un commentaire dans la description ci-dessus.
incroyable... des HEURES perdues à essayer d'obtenir ce travail et en fin de compte, la suppression de l'Image et de l'ajouter à nouveau, puis le paramètre de ressources, comme par "magie" travaillé... j'aime la façon dont je semble pour créer une application de travail en une heure, mais il me faut une journée entière pour mettre une image...!
OriginalL'auteur O. R. Mapper | 2014-01-09
Vous devez vous connecter pour publier un commentaire.
Une partie du problème est que WPF n'a pas de contexte permettant de résoudre cette URL. C'est une URL relative, et généralement, elle sera résolue par rapport à l'URI de base du contenu XAML dans lequel il est utilisé. Si j'utilise exactement la même URL, vous commencez avec ce code:
alors il fonctionne. C'est dans le code-behind pour
MainWindow
, évidemment.Avec un petit changement, le déplacement de cette ligne:
à la fin, puis-je obtenir le même
DirectoryNotFoundException
que vous.WPF essaie de résoudre cette URI d'une ressource réelle au point auquel vous attribuez la
BitmapImage
comme leSource
propriété de laImage
. Mon premier exemple fonctionne parce que lesImage
est dans l'arborescence visuelle, et donc, on reprend l'URI de base deMainWindow.xaml
, et décide que la ressource URI relative à cette URI de base.Si vous avez vraiment besoin pour créer le
Image
avant, il est associé à un visuel de l'arbre, vous avez différentes options. Vous pouvez réellement définir l'URI de base sur l'image:Cependant, c'est un peu bizarre. Il est plus facile de construire un URI absolu, par exemple:
Ces deux bien sûr supposer que vous savez ce que l'URI de base est. Vous pouvez le découvrir en posant des questions dans votre constructeur de MainWindow:
Dans votre cas, ce sera:
pack://application:,,,/ImageResTest;component/mainwindow.xaml
Il est ainsi clair que l'résolu URI doivent être:
pack://application:,,,/ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png
Fait intéressant, dites-vous que vous essayez et obtenez un message d'erreur. Eh bien, je suis en train exact URI, et je n'obtiens pas une erreur. Juste pour être clair, voici ma version modifiée de votre
MyClass
constructeur:et voici mon
MainWindow
constructeur:Cela fonctionne pour moi, après avoir suivi vos instructions. Si je vous comprends bien, vous en avez vu un
FileNotFoundException
lorsque vous faites cela. Cela me fait me demander si vos instructions ont omis quelque chose. E. g., Je m'attends à le voir cette erreur siImageResTestLib
a été nommé fortement. (Si vous voulez faire référence à une ressource dans une ferme nommée bibliothèque, vous avez besoin d'un complet d'affichage de l'assemblage de nom avant la;component
partie.)Une autre option serait d'utiliser
Application.GetResourceStream
, avec laBitmapImage.StreamSource
de la propriété. Mais là encore, on va avoir besoin d'un travail d'URL, de sorte que vous êtes susceptible de frapper le même problème que vous aviez avant. Une fois que vous déterminer ce qui est différent dans votre projet d'arrêt depack://application:,,,/ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png
de travail, puis l'approche de base que vous avez déjà devrait être bon.MyClass
constructeur (en fait, avec le code du constructeur et , je vois uneFileNotFoundException
indiquant que ImageResTestLib, Culture=neutral ou une de ses dépendances n'a pas pu être trouvée (voir mon edit de la question). Aucun des assemblées a un nom fort. Va continuer d'essayer des choses un peu plus.Oh, un moment - j'ai maintenant aussi essayé votre premier exemple de code (modifié
MainWindow
constructeur), et de même que les résultats de la même exception.Pourriez-vous essayer un couple de choses? 1: ajouter un
Debug.WriteLine(typeof(MyData.SomeStuff.MyClass).Assembly.GetName().FullName);
pour le constructeur de MainWindow et de montrer ce qu'il imprime? Aussi, quelle est laBaseUri
rapporté parMainWindow
? Enfin, pouvez-vous configurer Visual Studio pour casser quandXamlParseException
est levée, et ensuite utiliser la Pile d'Appel pour savoir ce que leAssemblyName assemblyRef
argument dans l'appel àAssembly.Load
?J'ai résolu mon problème et que c'était dû à quelque chose de complètement différent, que je voudrais appeler un bug dans VS et SharpDevelop. Si vous êtes intéressés, merci de voir mon EDIT3 pour une explication, où j'ai exposé ce que j'
Wow, c'est un nouveau sur moi. (Et la réponse à votre question précédente, comme j'imagine que vous le savez maintenant, oui, que l'URI absolu devrait généralement de travailler).
OriginalL'auteur Ian Griffiths