I've been wanting to blog about the application files and resources story in WPF, but couldn't get to it thus far. Recently I responded to a newsgroup question on how WPF (Avalon) handles resources, and figured that would make a good blog post until the WinFX SDK content for this goes online.
Update [Apr 2009]: If you came here looking for resources and URIs in Silverlight, then you will find
this post helpful. Note that Silverlight does not support pack URIs. If you're curious about resources in WPF or even as a historical perspective of what we enabled in the resource resolution and loading space in WPF before we created the subset in Silverlight, then read on.
BackgroundResources are non-executable data deployed with an application. They may take the form of images displayed in the UI or message strings for error messages. The .NET Framework provides built-in support for creating, localizing, packaging and deploying resources. You can create resources in a
.resx
or a
.resources
file. The .resx resource file format consists of XML entries to specify objects and strings. If your application has an image, the binary form of that image is serialized into the .resx file. But although a .resx file can be edited via a text editor, it cannot directly be added to an application executable or satellite assembly. You must first convert it to a .resources file using a tool like
ResGen.exe and add the .resources file into the assembly. The
GenerateResource
task in MSBuild handles the conversion of .resx to .resources at build time. In your WinForms project, you'd specify the
EmbeddedResource
build action for .resx files.
For e.g.
<EmbeddedResource Include="myResources.resx"/>
How we do it in AvalonIn Windows Presentation Foundation, the resource definition and loading model is different from the WinForms model. First, we do not require you to create .resx files. You merely indicate your resources in the project file and the WPF build system will take care of the rest. Second, unlike with .NET resources which have resource ids, in WPF you need to reference a resource in XAML via a Uri. WPF also supports the multi-lingual user interface (MUI) assembly model where language-neutral resources go into the main assembly and language-specific resources go into corresponding language-specific satellite assemblies. For these purposes, a new set of resource build actions were created. These are the
Resource
and
Content
build actions. Both these build actions target application files that are known at compile time.
ResourceIf a file is denoted 'Resource' in the project file, upon build, that file is embedded into the application assembly. Whether main or satellite assembly, depends on whether you've set the 'Localizable' meta-data. The default is main assembly.
For e.g.
<Resource Include="AmateurDictators/RoderickSpode.jpg"/>
The
ResourcesGenerator
task in the WPF MSBuild system (in Microsoft.WinFX.targets) creates a single .resources file for all Resources specified in the project. In a localized application, the application will load the resource from the appropriate satellite assembly based on the locale of the computer where it is running. In a future post I will talk about the resource fallback logic in WPF.
ContentIf a file is denoted as 'Content' with the appropriate 'CopyToOutputDirectory' meta-data set to 'Always' or 'PreserveNewest', the file is treated as loose application content and is copied to the build output directory, residing alongside the application assembly.
For e.g.
<Content Include="Drones/GussyFink-Nottle.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
Regardless of whether you denote a file as 'Resource' or 'Content', you can access it in markup and code via a simple relative Uri. For e.g.
<Image Source="AmateurDictators/RoderickSpode.jpg" />
<Image Source="Drones/GussyFink-Nottle.png" />
During build, a mapping of all Content files in an application is created. At runtime, when confronted with a relative Uri, the loading mechanism knows if the object is a loose Content file or a Resource embedded in the application assembly.
Files at site of originIf you do not want to be bound by the restrictions of having your application resources declared at compile time, there is another option for you. No, this doesn't involve using fully qualified Uris to reference resources over the internet. Although, that is indeed supported. WPF provides you with an abstraction for the application's conceptual site of origin i.e. the location from where the application was deployed. For instance, if your application was launched from
http://nerddawg.blogspot.com, then your application's site of origin is
http://nerddawg.blogspot.com. To access an image at
images/AuntDahlia.gif
at that location, you would specify in markup:
<Image Source="pack://siteoforigin:,,,/images/AuntDahlia.jpg" />
You can use the same Uri in code. For more on the Pack Uri syntax, see the Appendix in the
XPS spec. I will provide more details in a future post.
Choosing one over the otherYou would choose to mark a file as
Resource if:
- your file is localizable i.e. images with text in them, fonts or text files
- you don't expect to replace the file once the application has been built
- you don't want to deal with the task of managing and deploying the file separately from the application i.e. you want to be able to move the application around without having to worry about moving several associated files
And, you would choose to mark a file as
Content if:
- your file is not localizable
- you want the flexibility of replacing the file after the application assemblies have been built
- you want to be able to have the file download on demand (i.e. not with the application assembly)
- WPF cannot load a file of this type when it is embedded into the application assembly e.g. HTML content rendered in a Frame, media files
Finally, you would choose the
site of origin notation if:
- your file is not localizable
- you want the flexibility of replacing the file after the application assemblies have been built
- you want to be able to have the file downloaded only when requested
- you don't know the contents of the file (or you don't really have the file) when you build the application
- your file is very large and you don't want that to affect the application download time e.g. large media files
- WPF cannot load a file of this type when it is embedded into the application assembly e.g. HTML content rendered in a Frame, media files
There is currently no support for strongly typed 'Resource' and 'Content' files in the WPF project templates. 'EmbeddedResources' are supported, however, they cannot be referenced via Uris.
Tags: WinFX
Email this | Bookmark this