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 un DirectoryNotFoundException est levée, disant qu'une partie du chemin C:\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 un IOException dire que la ressource mydata/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 un FileNotFoundException dire que ImageResTestLib, 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 un DirectoryNotFoundException dire que C:\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.

Vos instructions mettre 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