How to set resource resource URI from code

I am trying to embed PNG graphics in a DLL and load it into Image control as BitmapImage . However, WPF continues to throw an exception saying that the resource was not found.

Firstly, some minimal sample code and 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 file with the code in 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 described above, so everything discussed here is in the same root namespace).

  • Add links from ImageResTestLib to PresentationCore, PresentationFramework, System.Xaml and WindowsBase.
  • Add a link from ImageResTest to ImageResTestLib.
  • Inside ImageResTestLib, add the folder hierarchy MyData/SomeStuff/Resources .
  • In the SomeStuff folder SomeStuff add the following MyClass.cs file:

     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 named Img.png and set its build action to Resource (as suggested, for example, here ).

So far, so good - starting this application should create a window that creates an instance of MyClass and retrieves the Image created by the instance of MyClass . This image must be filled with the BitmapImage symbol, the data of which was loaded from a graphic object included as a resource.

Unfortunately, there seems to be something wrong with the resource URI. The MSDN documentation has not yet helped.

I have tried the following resource URI options:

  • The form shown in the code example above - /AssemblyName;component/Path/Filename was proposed here and here , but a DirectoryNotFoundException is thrown, saying that part of the path is C:\ImageResTestLib;component\MyData\SomeStuff\Resources\Img.png not found.
  • pack://application:,,,/MyData/SomeStuff/Resources/Img.png was proposed here , here , here and here , but it throws an IOException that the resource mydata/somestuff/resources/img.png not found.
  • pack://application:,,,/ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png also proposed here as well as here , but throws a FileNotFoundException saying that ImageResTestLib, Culture=neutral or one of its dependencies was not found .
  • Resources/Img.png (relative to the code file) is implied here and here , but throws a DirectoryNotFoundException stating that C:\Users\myusername\Documents\Test\DOTNET\WPFTest\ImageResTest\bin\Debug\Resources\Img.png not found.
  • mydata/somestuff/resources/img.png (relative to the project), also implied here , behaves similarly to the previous one.

As none of them will work, I tried the following workaround based on ResourceDictionary :

  • Add a WPF resource dictionary named MyClassResources.xaml to the SomeStuff folder.
  • In this dictioanry resource, add a BitmapImage resource with the img key.
  • Modify the contents of MyClass.cs as follows:

     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 specified URI (when deleting the contents of the resource dictionary, the download is completed successfully). However, PNG graphics are still not found when using a path such as /ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png .

What am I doing wrong and how can I download the appropriate resources (if possible, without an additional resource dictionary)?




EDIT: Additional Information:

  • I am using German Windows 7 x64
  • .NET 4.0 Client Installed as Target Infrastructure
  • To make sure, I tried to create and run this from both Visual Studio 2010 and SharpDevelop 4.3.3; both times lead to the same exception.

On the FileNotFoundException stack FileNotFoundException I get Ian- based code:

 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:

Adding

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

for the designer of the main window, the following output is displayed:

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

Call

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

prints the following:

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



EDIT3:

While the accepted answer solves the problem described in this question, the actual reason why I could not see my graphics in my actual project was completely different:

So far, neither VS 2010 nor SharpDevelop give any indication of this, resources marked as Resources actually have a logical name (in my case, they saved it when I previously set the assembly action in EmbeddedResource and changed the logical name). The logical name still appears in the <LogicalName> element in the MSBuild file and from what I can see in ILSpy , this is what is actually used as the resource name in the compiled assembly.

The correct (working) URI resource for such a resource with a logical name seems

 /MyAssembly;component/LogicalResourceName 

(thus replacing the directory path with a resource, as usual, for EmbeddedResource resources)

While it is not possible to change the logical name in VS or SharpDevelop, while the assembly action is set to "Resource", deleting the resource and re-adding the file, and then setting the assembly action to "Resource", create a URI based on the file names, work again, so as a logical name will no longer be in the project file. Similarly, manually deleting the <LogicalName> element from the MSBuild file should work.

+9
resources wpf code-behind
Jan 09 '14 at 14:17
source share
1 answer

Part of the problem is that WPF has no context to resolve this URL. This is a relative URL, and generally it will be resolved relative to the base URI of the XAML content in which it was used. If I use the exact same URL that you start with this code:

 public MainWindow() { InitializeComponent(); var img = new Image(); Content = img; 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; } 

then it works. This is obviously in codebehind for MainWindow .

With one tiny change, moving this line:

 Content = img; 

to the end, then I get the same DirectoryNotFoundException as you.

WPF tries to resolve this URI to the actual resource at the point where you assign BitmapImage as the Source property of this Image . My first example works because Image is in a visual tree, so it picks up the base URI of MainWindow.xaml and solves this resource URI with respect to this base URI.

If you really need to create an Image before it is associated with the visual tree, you have various options. In fact, you can set the base URI on the image:

 img.SetValue(BaseUriHelper.BaseUriProperty, baseUri); 

However, this is strange. It is easier to just create an absolute URI, for example:

 bmp.UriSource = new Uri( baseUri, @"/ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png"); 

Both of these, of course, assume that you know what a basic URI is. You can find out by asking in the MainWindow constructor:

 public MainWindow() { InitializeComponent(); var baseUri = BaseUriHelper.GetBaseUri(this); ... 

In your case it will be: pack://application:,,,/ImageResTest;component/mainwindow.xaml

This, in turn, makes it clear that URI should have been resolved: pack://application:,,,/ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png

Interestingly, you say try this and get an error message. Well, I'm trying to make an exact URI, and I am not getting an error. For clarity, here is my modified version of the MyClass constructor:

 public MyClass(Uri baseUri) { img = new Image(); var bmp = new BitmapImage(); bmp.BeginInit(); bmp.UriSource = new Uri(baseUri, @"/ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png"); bmp.EndInit(); img.Source = bmp; img.Width = bmp.PixelWidth; } 

and here is my MainWindow constructor:

 public MainWindow() { InitializeComponent(); var obj = new MyData.SomeStuff.MyClass(BaseUriHelper.GetBaseUri(this)); this.Content = obj.Img; } 

This works for me following your directions. If I understand you correctly, you will see a FileNotFoundException when you do this. It makes me think about something missing from your instructions. For example, I would expect to see this error if ImageResTestLib was strongly named. (If you want to reference a resource in a strongly named library, before the part ;component you need a full description of the display of the assembly).

Another option is to use Application.GetResourceStream along with the BitmapImage.StreamSource property. But then again, this will require a working URL, so you will probably run into the same problem as before. After you develop something in your project that differs from what stops pack://application:,,,/ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png from work, then the basic approach that you already have to be good.

+16
Jan 09 '14 at 15:15
source share



All Articles