Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

At design time pack uri is valid, but not at runtime?

I'm setting a Button's content to an Image. It looks something like this:

<Button>
   <Image Source="pack://application:,,,/NavigationImages/nav_up_left.png" />
</Button>

In my project I have a subfolder named NavigationImages and within that folder is the image file nav_up_left.png.

When I view the Designer the image appears, however during runtime I get an IOException error saying it cannot locate the resource.

The Build Action is set to Resource.

Actually, this worked fine in one project. But when I copied it over the another project it fails. This seems like an incredibly simple problem, but I find myself stumped and ready to start pulling out hair. @_@

Your thoughts and suggestions will be much appreciated!

like image 424
Ashley Grenon Avatar asked Jul 26 '11 20:07

Ashley Grenon


4 Answers

I just struggled with this same problem for quite a while, and I think that part of what was going wrong in the original was the missing word "component". I, for instance, had

myBitmapImage.UriSource = new Uri(@"pack://application:,,,/MyApp;images/mona2.jpg");

but should have had

... = new Uri(@"pack://application:,,,/MyApp;component/images/mona2.jpg");

The word "component" is not part of the pathname, despite its appearance -- it's a string literal that has to be there. Why? Someone thought it'd be a good idea, I guess.

And for those struggling with another part of the thing, what about "MyApp"? That's the name of the Assembly. Right-click on your project name, select "Properties...", and under the "Application" tab you'll see the "Assembly name:" field.

If you don't feel like searching for that (or worry that it might change, breaking your code), you can do this:

String appUri = @"pack://application:,,,/" + 
                  System.Reflection.Assembly.GetEntryAssembly().GetName().Name + ";";
String path = appUri + "component/images/mona2.jpg";
myBitmapImage.UriSource = new Uri(path);

Not very pretty code, I admit -- it can clearly be shortened -- but it'll gets you where you need to go, I hope. Remember to set the "Build" property on your image file to "Resource"!

like image 163
John Avatar answered Oct 07 '22 04:10

John


Whelp, I figured it out...kinda.

I copied that xaml code from one project where the output type is Windows Application, to another project where the output type is Class Library.

I didn't think of it at the time, but apparently when the output type is a Class Library the pack URI needs to change.

So instead of "pack://application:,,,/NavigationImages/nav_up_left.png" I changed it to "/ProjectName;component/NavigationImages/nav_up_left.png" and now it's working just fine.

I'm not 100% clear why this is works and not the former. I've read through the MSDN documentation on pack URIs in WPF but perhaps I misinterpreted something.

I'll leave this answer unchecked in the event someone can give me a good explanation why what I previously had doesn't work in a project with output type Class Library.

I'm probably missing something really simple. @_@

like image 43
Ashley Grenon Avatar answered Oct 07 '22 06:10

Ashley Grenon


Just to shine a light on what was happening in your situation. The second pack uri. The one that worked. Is meant for resources located in an assembly other than the host application. By the sounds of it, the host application was loading this resource from the Class Library in question?

You can see the differences in the pack uri schemes here: MSDN Pack URI Scheme

The uri changes slightly when referencing a resource from the main assembly, and referencing one from another assembly.

Also, the pack://application:,,, includes what is referred to as the "authority", to omit it would basically make it a relative path, both are valid in most cases where the application authority is assumed.

EDIT: basically because /Subfolder/Resource.xaml(.jpg etc.) and /Assembly;component/Resource.xaml are very similar, the latter tells the parser/loader that it's looking in a referenced assembly, not in the main application's assembly. (I imagine this helps speed up the search).

like image 34
SilverX Avatar answered Oct 07 '22 05:10

SilverX


One other solution to getting this right:

Once your image Build Action is set to 'Resource' and you have rebuilt, navigate to the properties of your <Image /> object. The properties window will provide a ... file resource browser, whereupon selecting your image the Source="..." attribute of your <Image /> will be correctly filled in.

like image 26
DuckMaestro Avatar answered Oct 07 '22 05:10

DuckMaestro