I am trying to embed a PNG graphic into a DLL and load it into an Image
control as a BitmapImage
. However, WPF keeps throwing an exception saying that the resource cannot be found.
First, some minimal sample code and the steps to reproduce the problem:
Create a WPF project named ImageResTest with an empty main window (you can set the default namespace to
ImageResTest
). The code-behind file of the main window should look like this: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; } } }
Create a class library named ImageResTestLib (you can set the default namespace to
ImageResTest
, as above, so everything discussed here is in the same root namespace).- Add references from ImageResTestLib to PresentationCore, PresentationFramework, System.Xaml and WindowsBase.
- Add a reference from ImageResTest to ImageResTestLib.
- Inside ImageResTestLib, add the folder hierarchy
MyData/SomeStuff/Resources
. In the
SomeStuff
folder, add the following file 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 the
Resources
folder, add a PNG file namedImg.png
and set its build action to Resource (as suggested, for example, here).
So far, so good - launching this application should create a window which instantiates MyClass
and retrieves an Image
created by that MyClass
instance. That image should have been filled with a BitmapImage
whose data was loaded from the graphic included as a resource.
Unfortunately, there seems to be something wrong with the resource URI. The documentation on MSDN has not helped so far.
I have tried the following variants of resource URIs:
- The form depicted in the code sample above -
/AssemblyName;component/Path/Filename
- was suggested here and here, but aDirectoryNotFoundException
is thrown, saying that a part of the pathC:ImageResTestLib;componentMyDataSomeStuffResourcesImg.png
was not found. pack://application:,,,/MyData/SomeStuff/Resources/Img.png
was suggested here, here, here and here, but throws anIOException
saying that the resourcemydata/somestuff/resources/img.png
could not be found.pack://application:,,,/ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png
was also suggested here, as well as here, but throws aFileNotFoundException
saying thatImageResTestLib, Culture=neutral
or one of its dependencies was not found.Resources/Img.png
(relative from the code file) was implied here and here, but throws aDirectoryNotFoundException
saying thatC:UsersmyusernameDocumentsTestDOTNETWPFTestImageResTestinDebugResourcesImg.png
was not found.MyData/SomeStuff/Resources/Img.png
(relative to the project), also as implied here, behaves analogously to the previous one.
As none of these would work, I tried the following workaround based on a ResourceDictionary
:
- Add a WPF resource dictionary named MyClassResources.xaml in the
SomeStuff
folder. - In that resource dictioanry, add a
BitmapImage
resource with the keyimg
. Change the contents of MyClass.cs like this:
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; } } } }
Now, the resource dictionary can be loaded from the indicated URI (when removing the contents of the resource dictionary, loading completes successfully). However, the PNG graphics are still not found when using a path like /ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png
.
What am I doing wrong and how can I load the respective resources (if possible, without the extra resource dictionary)?
EDIT: Some more information:
- I am using a German Windows 7 x64
- .NET 4.0 Client is set as the target framework
- Just to make sure, I have tried building and running this both from within Visual Studio 2010 and SharpDevelop 4.3.3; both times resulting in the same exception.
The stacktrace of the FileNotFoundException
I am getting based on Ian's code is as follows:
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:UsersusernameDocumentsTestDOTNETWPFTestImgResTestLibMyDataSomeStuffMyClass.cs:Zeile 36.
bei ImageResTest.Window1..ctor() in c:UsersusernameDocumentsTestDOTNETWPFTestImageResTestWindow1.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.Win