Organizing and referencing assets (images, fonts, xaml) has always been an interesting topic of discussion. There is still no proper guidance and is wide open for experimentation.
Organizing assets
If you have few assets, you could just keep them under a folder in your main assembly. However if you have a variety of assets and in large numbers, you are better off keeping them in separate assemblies. Each assembly can now serve as a theme for your application. Within the assembly you could break up your assets into a folder structure. As a simple example, you could have a structure like so:
![]()
You can come up with a more elaborate structure depending on the variety and the number of assets that you have. Since this post is more about referencing assets than organizing them, I am going to jump to that now. I assume you already have a folder structure for your assets that is similar to the one I mentioned above.
Referencing assets
If you are to store your assets in a separate assembly, the referencing Uri can be rather long, something like:
pack://application:,,,/Company.ThemeName;component/Images/Icons/Large/up.png
Try typing few of those Uri’s and I can guarantee the beginnings of a Carpal tunnel
. This is where a MarkupExtension can be very useful. It will abstract out those long paths and only keep the part that is essential. So you could be seeing something like:
<ImageBrush x:Key="SelfFill" ImageSource="{ln:Asset Icons/marker/self_fill.png}" />
Surely this is more readable than the previous path. If you are a bit more adventurous, you can also add a prefix to the path that will further abstract the actual location of the resource. For example the above MarkupExtension usage could be: {ln:Asset MarkerIcons:self_fill.png}. Note the MarkerIcons: prefix, which will internally map to the Images/Icons/marker path. You can come up with your own prefixes that will simplify the paths, as you see fit for your project.
The AssetExtension class contains the logic to parse the paths and create the appropriate resources. Just like every other MarkupExtension, the ProvideValue() method is where the bulk of the logic is. In the case of AssetExtension, there is a Regex that parses the path and identifies the kind of resource we are dealing with.
Here is the Regex that I am using:
private static Regex ResourceRegex = new Regex( @" (?<Image>(.png|.jpg|.bmp)$) | (?<Font>#.+$) | (?<Xaml>.xaml$) ", RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
Once we know the resource-type, we create it inside of ProvideValue() and return that as the output. The core methods are below. ResourceType is an enum that I am using internally.
public static Uri GetResourceUri(string path) { string asmName = Assembly.GetExecutingAssembly().GetName().Name; string uriString = string.Format("pack://application:,,,/{0};component/{1}", asmName, path); Uri uri = new Uri(uriString); return uri; } public override object ProvideValue(IServiceProvider serviceProvider) { IProvideValueTarget ipvt = serviceProvider.GetService(typeof (IProvideValueTarget)) as IProvideValueTarget; if (ipvt == null) return null; ResourceType type = ParseResourceType(Path); switch (type) { case ResourceType.Image: BitmapImage image = new BitmapImage(GetResourceUri(Path)); return image; case ResourceType.Font: FontFamily family = new FontFamily(GetResourceUri(""), Path); return family; case ResourceType.Xaml: return GetResourceUri(Path); } return null; } private ResourceType ParseResourceType(string path) { ResourceType type = ResourceType.None; Match match = ResourceRegex.Match(path); if (match.Groups["Image"].Success) type = ResourceType.Image; else if (match.Groups["Font"].Success) type = ResourceType.Font; else if (match.Groups["Xaml"].Success) type = ResourceType.Xaml; return type; }
Summary
So if you have project that uses a ton of assets, it is probably easier to use a MarkupExtension to reference them instead of hard-coding paths. Besides simplifying the paths, it also helps you in refactoring. If you wish to relocate the assets to a different assembly or change the folder structure, it is much easier now, since you only change the AssetExtension.
The attached source file contains all the code. Note that it does not contain the code for parsing prefixes. I’ll leave that as an exercise for the readers!

You can actually just return GetResourceUri(Path), and the resulting string will be handled exactly as if you had just typed the entire pack URI in the Xaml. That means image and font URIs will still get properly converted (e.g. WPF will cook up an ImageSource for you if you return a URI to an image file).
The real potential in your solution is that you have the opportunity to do caching. If all of your assets are loaded with this extension, you should consider keeping a lookup table that maps asset paths to weak references of those assets. That way, if they get reused (which many do), you’re not loading them multiple times.
There is another option to consider. You could register a custom web request handler. If create a web request factory that implements IWebRequestCreate, you can register it to handle a custom URI scheme (see WebRequest.RegisterPrefix(…)). Then you could replace your markup extensions with simple URIs, like “asset:///Images/marker/self_fill.png”. You’ll need to implement a custom WebResponse that overrides GetResponseStream(). I ended up doing this for a project where resources were organized in a virtual file system. I needed to check different relative locations in priority order. It worked out rather well.
That’s a useful thing to have Mike. When using the AssetExtension, I am aware of where it is being used, so the caching part is kind of redundant. Although I love the idea and I may find it useful when returning references of other kinds.
I tried returning the Uri directly but it causes exceptions. That’s the reason why I had to create them myself. I’ll give it a shot again just to confirm.
The WebRequest thing is interesting and would love to try that.
Pavan, it seems you’re right about an exception being thrown when you return just the URI. I may have been remembering incorrectly. I think I actually tried a different approach where I used a value converter to convert the “short” path to the fully qualified resource URI, like so:
Obviously, this isn’t much better than typing the full URI, which is why I went on explore other options.
As for the caching, I simply meant that if you are using the same image in multiple places in your application (for example), your extension could cache a weak reference when it creates the first BitmapImage, and then return the same cached instance in subsequent requests for the same image (if the reference is still alive). That would save you some video memory in theory. It’s possible that WPF uses a bitmap caching system internally that I’m unaware of.
Whoops, my example Xaml got stripped out:
[Image Source="{Binding Source='Images/splash.png', Converter={StaticResource ResourcePathConverter}}" /]
A-ha, now I remember how I did it before. I used a Binding inside my markup extension to leverage WPF’s built-in value converters:
public override object ProvideValue(IServiceProvider serviceProvider)
{
var binding = new Binding
{
Source = GetResourceUri(Path),
BindsDirectlyToSource = true
};
return binding.ProvideValue(serviceProvider);
}
I was thinking of going the route of using Converters but then realized its just unnecessary indirection and I could just save some CPU cycles too
.
The Binding option is also interesting. If I may suggest, you should also set the Mode to OneTime, just for good measure.
The suggestions about Caching and WebRequest are the most interesting. I am definitely going to try them out.
I agree, the custom URI scheme is a really fun exercise. Not only is it cool to have WPF “automagically” recognize your own custom URI format, but it’s also the most lightweight implementation. That is, after all, how pack URIs are handled (see PackWebRequest and PackWebResponse for reference). A custom-tailored implementation should be even more efficient and flexible
. You can also register your handler in your App.config file rather than relying solely on a runtime call to WebRequest.RegisterPrefix().
Thanks for the article Pavan. I was using the direct link approach till now and my application uses a lot of small images. I changed by solution to use resource extensions and I feel this way is a much better and maintainable way of accessing resources.
BTW: Returning a BitmapImage at all places caused exceptions for me (specially in custom controls) so I took Mike’s way by using Binding as the return value and solved the issue. Thanks to Mike for the resolution.
A welcomed extension! If you do not specify the parameter name “Path=” in the XAML, have you seen – and do you know why – VS08 warns that “No constructor for AssetExtension has 1 parameter”? If you include the parameter name “Path=” that warning goes away. Cheers.