views:

5023

answers:

1

My assembly includes an image with BuildAction==Resource. I want to obtain a BitmapImage from this embedded resource.

I can load a BitmapImage from file like this:

var bitmap = new BitmapImage(new Uri(path));

But how to I create a Uri that will refer to an embedded resource image?

When I try and create a 'pack URI' (for example pack://application:,,,/MyImage.png or pack://application:,,,/MyAssembly;component/MyImage.png), an exception is thrown:

System.UriFormatException "Invalid URI: A port was expected because of there is a colon (':') present but the port could not be parsed."

I found the fix, to the UriFormatException in this blog post

However, with that fix applied, I still get exceptions trying to load a BitmapImage from a pack URI.

When using the pack://application:,,,/Image.png format, I get a NullReferenceException, and when using the pack://application:,,,/AssemblyName;component/Image.png format, I get a NotSupportedException "The Uri prefix is not recognized".


Summary My problem was that I was trying to use a 'pack URI' in a process before any WPF control/window/etc had been instantiated, so the 'pack' URI scheme was not yet registered (other WPF required 'stuff' must also not be set too, because manually registering the pack scheme doesn't itself fix the problem). The solution was to wait until after instantiating my WPF usercontrol to use pack URIs.

+2  A: 

This MSDN page has all the information you might want to know about resource URIs in WPF (often called pack URIs). You're going to want to use relative URIs more often probably, so see Table 4, which should be of particular use.

If you want a briefer overview of resource (pack) URIs, see this blog post. It shows that syntax is indeed relatively simple:

pack://application:,,,/ResourceFile.xaml

pack://application:,,,/ReferencedAssembly;component/ResourceFile.xaml

However, there are a few quirks to work out (in my experience), so often finding the correct resource URI requires a bit of experimentation.

Noldorin
@mackenir: Did you ever consider that the URL you posted in your *edited* question hadn't yet appeared at the time I wrote my response. Rudeness isn't going to get you a good answer.
Noldorin
Sorry! I forgot I'd edited the question, believe it or not.
mackenir
@mackenir: No worries, in that case. Have you tried simply using a relative URI, aa shown in Table 4 on the MSDN page? You might have more luck with that...
Noldorin
I'll try relative URIs but I think they may be interpreted as file paths. It appears a string that's an absolute file path is interpreted as such, so Im thinking a plain string with no uri scheme is considered a file path.
mackenir
@mackenir: Last time I wrote an WPF app (actually, it was Silverilght, but it all works the same), I had no trouble dynamically loading resources (images, indeed) using relative URIs, and I was doing it across different assemblies too. If you're not having any luck, I'll see if I can dig that code out.
Noldorin
It seems that when I specify a Uri in the relative format, the BitmapImage constructor interprets it as a file path. eg new Uri("/Image.png", UriKind.Relative) is interpreted as c:\Image.png. Maybe the BitmapImage constructor doesnt properly deal with pack URIs.
mackenir
I'm going to fire up a simple test app to confirm that these things normally work! I am using WPF in a 'non-WPF' process (so not a WPF 'Application') so maybe things don't work properly.
mackenir
I found that all the following URIs worked in a test WPF Application:new Uri("/Image.png", UriKind.Relative)new Uri("Image.png", UriKind.Relative)new Uri("pack://application:,,,/Image.png", UriKind.Absolute)new Uri("pack://application:,,,/WpfApplication5;component/Image.png", UriKind.Absolute)So it must be a problem with the hosting process (it's running in a Visual Studio addin)
mackenir
@mackenir: Yeah, that would explain a lot of the issues you are having. I'll give it some thought and hopefully have an answer soon.
Noldorin
Ahah. I think I know what the problem is. I am trying to use pack URIs before I've instantiated a WPF control. Should be able to rejig the code so that doesn't happen.
mackenir
...and since my WPF is in an assembly that's loaded up dynamically by a process, I need to use absolute pack URIs that specify my assembly name.
mackenir