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 NamenImg.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 einDirectoryNotFoundException
geworfen wird, die besagt, dass ein Teil des PfadesC:\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 einIOException
sagen, dass die Ressourcemydata/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 eineFileNotFoundException
sagen, dassImageResTestLib, 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 eineDirectoryNotFoundException
sagen, dassC:\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üsselimg
. -
Ä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
imImageRestTestLib
Komponente, aber dein Quelltext zeigt den namespace alsImageRestTest
, was bedeutet, es ist in der HauptsacheImageRestTest
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...!
Du musst angemeldet sein, um einen Kommentar abzugeben.
Teil des Problems ist, dass die WPF hat keinen Zusammenhang mit denen zu lösen, die URL. Es ist eine relative URL, und in der Regel, es würde behoben werden relativ zum Basis-URI des XAML-Inhalt, in dem es verwendet wird. Wenn ich genau die gleiche URL, die Sie beginnen mit, in diesem code:
dann funktioniert es. Das ist in der codebehind für
MainWindow
offensichtlich.Mit einer kleinen änderung, verschieben Sie diese Zeile:
bis zum Ende, dann bekomme ich die gleiche
DirectoryNotFoundException
als Sie.WPF versucht zu beheben, die URI einer Ressource an den Punkt, an dem Sie ordnen die
BitmapImage
alsSource
Eigenschaft, dassImage
. Meinem ersten Beispiel funktioniert, weil dieImage
ist in der visuellen Struktur, und so nimmt die Basis-URIMainWindow.xaml
, und beschließt, dass Ressourcen-URI relativ zu diesem Basis-URI.Wenn Sie wirklich brauchen, um das
Image
bevor es dazu kommt, verbunden mit einer visuellen Struktur, hast du verschiedene Optionen. Sie könnte tatsächlich die Basis-URI auf dem Bild:Allerdings, das ist irgendwie komisch. Es ist einfacher, nur zu konstruieren, die eine absolute URI, z.B.:
Beide selbstverständlich davon aus, dass Sie wissen, was die Basis-URI ist. Sie können feststellen, dass Sie bitten, in Ihrem MainWindow-Konstruktor:
In deinem Fall werden:
pack://application:,,,/ImageResTest;component/mainwindow.xaml
Dies wiederum macht deutlich, was mit der aufgelösten URI sein sollte:
pack://application:,,,/ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png
Interessant, Sie sagen, Sie versuchen, und bekommen eine Fehlermeldung. Nun, ich versuche, die genaue URI, und ich bin nicht immer ein Fehler. Nur um klar zu sein, hier meine geänderte version der
MyClass
Konstruktor:und hier ist mein
MainWindow
Konstruktor:Dies funktioniert für mich, mit folgte Ihren Anweisungen. Wenn ich Sie richtig verstehe, sehen Sie eine
FileNotFoundException
wenn Sie dies tun. Das macht mich Frage mich, ob Ihre Anweisungen haben etwas weggelassen. E. g., Ich würde erwarten, um zu sehen, diesen Fehler, wennImageResTestLib
stark war, benannt. (Wenn Sie möchten, verweisen auf eine Ressource, die stark mit dem Namen Bibliothek, benötigen Sie einen vollständig qualifizierten Montage-Anzeigenamen, bevor die;component
Teil.)Andere Möglichkeit wäre die Verwendung von
Application.GetResourceStream
zusammen mit denBitmapImage.StreamSource
Eigenschaft. Aber das ist wieder gehen zu müssen, eine funktionierende URL, so dass Sie wahrscheinlich treffen wird, das gleiche problem als Sie vorher hatten. Sobald Sie herausfinden, was ist anders in Ihrem Projekt, dass hältpack://application:,,,/ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png
von der Arbeit, dann ist der grundlegende Ansatz, den Sie bereits haben sollte in Ordnung sein.MyClass
Konstruktor (eigentlich, mit diesem Konstruktor code und , ich sehe eineFileNotFoundException
darauf hinweist, dass ImageResTestLib, Culture=neutral oder eine Ihrer Abhängigkeiten konnte nicht gefunden werden (siehe meine edit-Frage). Keiner der beteiligten Assemblys mit starkem Namen. Werde weiterhin versuchen, einige weitere Dinge.MainWindow
Konstruktor), und auch, dass die Ergebnisse in der gleichen Ausnahme.Debug.WriteLine(typeof(MyData.SomeStuff.MyClass).Assembly.GetName().FullName);
auf die MainWindow-Konstruktor und zeigen, was es druckt? Auch, was dieBaseUri
berichtet vonMainWindow
? Schließlich konnte Sie konfigurieren Visual Studio zu brechen, wennXamlParseException
geworfen wird, und verwenden Sie dann die Call-Stack, um herauszufinden, was dieAssemblyName assemblyRef
argument im AufrufAssembly.Load
?XamlParseException
enthält keine Aufrufe zuAssembly.Load
. Die inner exception ist einFileNotFoundException
dessen Aufruf-stack enthält einen call-toAssembly.Load
, konfiguriert, damit ich VS zu brechen, wennFileNotFoundException
geworfen wird, als gut. Es macht jetzt Pause für dieFileNotFoundException
, und Kopieren-Ausnahme detail in Zwischenablage kopieren zeigt den AufrufAssembly.Load
jedoch die VS Call-Stack Ansicht nicht; es zeigt ein ganz anderes call-stack.FileNotFoundException
als Zwischenablage kopiert von VS sind Anrufe zuRuntimeAssembly._nLoad
,RuntimeAssembly.nLoad
undRuntimeAssembly.InternalLoadAssemblyName
. Die ersten drei Zeilen in der Call-Stack "Ansicht" Aufrufe an dieBitmapSource.CompleteDelayedCreation
,BitmapSource.PixelWidth.get
und nach einem native zu managed und managed zu native übergang, zuRuntimeType.CreateInstanceSlow
.ImgResTestLib
während ich früherImageResTestLib
in meine Ressourcen-URIs. Nach der Korrektur der letzteren, Ihre Lösung funktioniert in meiner minimal-Beispiel. Bedeutet das, dass eine absolute URI, beginnend mitpack://application:,,,/...
sollte in der Regel funktionieren? (Ich bin fragend, denn ich kann nicht finden, eine solche Benennung Fehler in meinem eigentlichen Projekt, und es funktioniert immer noch nicht, obwohl ich scheinen unfähig zu sein, um das problem zu reproduzieren in einem minimal-Beispiel. Die Annahme dieser Antwort dennoch becaue Sie Tat, was ich lösen können, zeigte sich in der Frage.)