Wie die Bild-Ressource-URI aus Code-Behind

Ich versuche einbetten eine PNG-Grafik in eine DLL und lade es in ein Image Kontrolle als BitmapImage. Jedoch, WPF hält, eine Ausnahme zu werfen, die sagen, dass die Ressource kann nicht gefunden werden.

Zunächst einige minimale Beispielcode und die Schritte zu reproduzieren des Problems:

  • Erstellen Sie ein WPF-Projekt mit dem Namen ImageResTest mit einem leeren Hauptfenster (Sie können den Standard-namespace zu ImageResTest). Die code-behind-Datei der main-Fenster sollte wie folgt Aussehen:

    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;
            }
        }
    }
  • Erstellen Sie eine Klassenbibliothek mit dem Namen ImageResTestLib (Sie können den Standard-namespace zu ImageResTest wie oben beschrieben, also alles, was hier erörtert wird, in der gleichen root-namespace).

  • Verweise hinzufügen von ImageResTestLib zu PresentationCore, PresentationFramework, System.Xaml und WindowsBase.
  • Fügen Sie einen Verweis aus ImageResTest zu ImageResTestLib.
  • Innen ImageResTestLib, fügen Sie die Ordner-Hierarchie MyData/SomeStuff/Resources.
  • In der SomeStuff Ordner, fügen Sie die folgende Datei 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;
                }
            }
        }
    }
  • In der Resources Ordner, fügen Sie eine PNG-Datei mit dem Namen Img.png und setzen Sie dessen build action auf Ressource (wie vorgeschlagen, zum Beispiel, hier).

So weit, So gut - starten Sie diese Anwendung sollte ein Fenster erstellen, die instanziiert MyClass und ruft eine Image erstellt, die MyClass Instanz. Das Bild gefüllt sein sollte mit einem BitmapImage deren Daten geladen von der Grafik als Ressource.

Leider, es scheint etwas falsch mit der resource-URI. Die Dokumentation auf der MSDN-Website nicht geholfen hat, so weit.

Ich habe versucht, die folgenden Varianten der Ressourcen-URIs:

  • Form dargestellt, im code-Beispiel oben - /AssemblyName;component/Path/Filename - wurde vorgeschlagen, hier und hier, aber ein DirectoryNotFoundException geworfen wird, die besagt, dass ein Teil des Pfades C:\ImageResTestLib;component\MyData\SomeStuff\Resources\Img.png wurde nicht gefunden.
  • pack://application:,,,/MyData/SomeStuff/Resources/Img.png wurde vorgeschlagen hier, hier, hier und hier, wirft aber ein IOException sagen, dass die Ressource mydata/somestuff/resources/img.png konnte nicht gefunden werden.
  • pack://application:,,,/ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png wurde auch vorgeschlagen hier, sowie hier, wirft aber eine FileNotFoundException sagen, dass ImageResTestLib, Culture=neutral oder eine Ihrer Abhängigkeiten wurde nicht gefunden.
  • Resources/Img.png (Verwandte aus der code-Datei) wurde stillschweigend hier und hier, wirft aber eine DirectoryNotFoundException sagen, dass C:\Users\myusername\Documents\Test\DOTNET\WPFTest\ImageResTest\bin\Debug\Resources\Img.png wurde nicht gefunden.
  • MyData/SomeStuff/Resources/Img.png (relativ zum Projekt), das auch als STILLSCHWEIGENDE hier, verhält sich Analog zu der vorherigen.

Da keine dieser arbeiten würde, habe ich versucht die folgende Vorgehensweise basiert auf einer ResourceDictionary:

  • Fügen Sie eine WPF-Ressourcen-Wörterbuch namens MyClassResources.xaml in der SomeStuff Ordner.
  • In die Ressource dictioanry, fügen Sie ein BitmapImage Ressource mit dem Schlüssel img.
  • Ändern Sie den Inhalt des MyClass.cs wie diese:

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

Nun, das resource-dictionary geladen werden kann von der angegebenen URI (beim entfernen der Inhalt der Ressource Wörterbuch, das laden erfolgreich abgeschlossen wurde). Aber die PNG-Grafiken sind noch nicht gefunden, wenn Sie mit einem Weg, wie /ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png.

Was mache ich falsch und wie kann ich die Belastung der entsprechenden Ressourcen (wenn möglich, ohne zusätzliche Ressourcen-Wörterbuch)?


EDIT: ein Paar weitere Informationen:

  • Ich bin mit einem deutschen Windows 7 x64
  • .NET 4.0 Client als Ziel-framework
  • Nur um sicher zu gehen, habe ich versucht, den Aufbau und die Ausführung dieser beiden innerhalb von Visual Studio 2010 und SharpDevelop 4.3.3; beide Male was in die gleiche Ausnahme.

Den stacktrace der FileNotFoundException ich bin immer basierend auf Ian's code ist wie folgt:

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:

Hinzufügen

Debug.WriteLine(typeof(MyData.SomeStuff.MyClass).Assembly.GetName().FullName);

dem Konstruktor des Hauptfensters ergibt die folgende Ausgabe:

ImgResTestLib, Version=1.0.5123.16826, Culture=neutral, PublicKeyToken=null

Den Aufruf

Debug.WriteLine(BaseUriHelper.GetBaseUri(this).ToString());

druckt die folgenden:

pack://application:,,,/ImageResTest;component/window1.xaml

EDIT3:

Während die akzeptierte Antwort löst das problem beschrieben, dass diese Frage, der eigentliche Grund, warum ich konnte nicht sehen, meine Grafik in meinem eigentlichen Projekt war ganz etwas anderes:

Während weder VS 2010 noch SharpDevelop geben alle Hinweis darauf, Ressourcen gekennzeichnet als Ressource tatsächlich einen logischen Namen (in meinem Fall, Sie behielten es aus, wenn ich hatte versuchsweise den Buildvorgang zu EmbeddedResource und verändert der logische name) ist. Der logische name erscheint noch in einer <LogicalName> element in der MSBuild-Datei und von dem, was ich sehen kann, in ILSpy, , dass ist, was tatsächlich dazu dienen, die Ressourcen-Namen in der kompilierten assembly.

Den richtigen (Arbeits -) Ressourcen-URI auf eine solche Ressource mit einem logischen Namen zu sein scheint

/MyAssembly;component/LogicalResourceName

(damit ersetzt das Verzeichnis Pfad zu der Ressource, wie üblich für EmbeddedResource Ressourcen)

Zwar ist es nicht möglich, ändern Sie den logischen Namen in VS oder SharpDevelop, während die build-Aktion festgelegt ist, zu Ressource, das entfernen der Ressourcen-und re-hinzufügen der Datei, dann wird die build action auf Ressource, macht die mit dem Namen-based-URIs wieder funktionieren, wie der logische name wird nicht in der Projekt-Datei nicht mehr. Ebenso das entfernen der <LogicalName> element manuell von der MSBuild-Datei funktionieren sollte.

  • Ihre Anweisungen stellen MyClass im ImageRestTestLib Komponente, aber dein Quelltext zeigt den namespace als ImageRestTest, was bedeutet, es ist in der Hauptsache ImageRestTest Projekt. Natürlich gibt es nichts hindert Sie mit verschiedenen namespaces, aber ich wollte überprüfen, im Fall, es war ein Fehler in der Anleitung.
  • Nein, das ist gewollt, also hier ist alles in der gleichen root-namespace. Danke für die Anmerkung; ich habe einen Kommentar Hinzugefügt, in der Beschreibung oben.
  • unglaublich... Verschwendete STUNDEN versucht, diese zu arbeiten und am Ende, löschen Sie das Bild und wieder hinzufügen, dann setzen Sie es auf die Ressource, "magisch" gearbeitet... ich Liebe es, wie ich scheinen, um erstellen Sie eine funktionierende Anwendung in einer Stunde, aber es nimmt mich einen ganzen Tag, um ein Bild hinein...!
InformationsquelleAutor O. R. Mapper | 2014-01-09
Schreibe einen Kommentar