Dear Dr. WPF,
We are running into some issues around application level resources when we attempt to put WPF task pane UI within Office. The primary issue is that the runtime host is not WPF in these cases which means that Application.Current.Resources is not available. That in turn affects how static resource references are handled in the xaml and how FindResource() works in code.
We’re curious if you have any viable solutions or experience with this type of situation. I’m guessing that in addition to Office/VSTO that Winforms hosted interop would have similar issues.
Thanks,
Brian
Dear Brian,
Managing application-level resources in an interop scenario like yours, where WPF is being hosted within another technology like Win32 or Windows Forms, definitely requires more work on the part of the developer. In this post I’ll describe a number of approaches that you might take and you can decide which is the most appropriate for your scenario.
Brief Intro to Resources and Resource Resolution
For those who may be new to WPF (or who may just want a refresher), this section contains a brief introduction to resources and resource resolution. Feel free to skip ahead if you’re already familiar with these concepts.
Each framework element (which means any descendant of FrameworkElement or FrameworkContentElement) has a Resources collection. This collection is of type ResourceDictionary. The ResourceDictionary type truly represents a CLR Dictionary in which each value (or resource) has a unique key.
The fact that every framework element has its own Resources collection allows resources to be defined at any level in the element tree.
<Grid Margin="20" x:Name="RootGrid"> <Grid.Resources> <Storyboard x:Key="FadeOutGlassStoryboard" TargetProperty="Opacity"> <DoubleAnimation To="0" Duration="0:0:0.5" /> </Storyboard> </Grid.Resources> . . . <StackPanel> <StackPanel.Resources> <Style TargetType="{x:Type ListBoxItem}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ListBoxItem}"> <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" /> </ControlTemplate> </Setter.Value> </Setter> </Style> </StackPanel.Resources> . . . </StackPanel> </Grid>
In addition, resources can be defined at the application level within a markup file called an application definition file:
<Application x:Class="WindowsApplication1.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" StartupUri="Window1"> <Application.Resources> <ResourceDictionary> <Style x:Key="{x:Type GridSplitter}" TargetType="{x:Type GridSplitter}"> <Setter Property="IsTabStop" Value="False" /> </Style> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="Resources\ConverterResourceDictionary.xaml"/> <ResourceDictionary Source="Resources\LogoDictionary.xaml"/> <ResourceDictionary Source="Resources\ColorsResourceDictionary.xaml"/> <ResourceDictionary Source="Resources\IconResourceDictionary.xaml"/> <ResourceDictionary Source="Resources\SimpleStyles.xaml"/> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> </Application>
And finally, resources can be defined at the theme level. In addition to the built-in Windows themes, control libraries might define their own theme-level resources.
So there are several levels at which resources may be defined. Now let’s look at how you use (a.k.a., reference) resources.
In markup, a resource reference can be either static or dynamic. There are slightly different rules that apply to each:
- A static reference is applied to a property in XAML by using the {StaticResource xxx} markup extension and a dynamic reference is applied via the {DynamicResource yyy} extension, where xxx and yyy represent the respective resource keys.
- A static reference can be used to set any CLR property, whereas a dynamic reference can only be used to set dependency properties on framework elements or freezables or to set the Value property of Setter objects in styles.
- Static resource references are resolved at parse time (for the most part), whereas dynamic references are resolved at run time. This means a static reference can only be used if the resource has been parsed before the reference, whereas a dynamic reference can be used as a forward reference for a resource that is defined later.
The process of resource resolution begins with the referencing element. First, the Resources collection of the referencing element is checked. If a dynamic reference was used and the element has a Template and/or Style, the Resources collections of the Template and Style are also checked. If the resource was not found, resource resolution then continues up the element tree by searching the Resources collections of each parent until the resource is found.
Resource resolution always favors the logical tree. (If an element does not have a logical parent, resolution will begin through the visual tree until an ancestor is found in the logical tree and it will then continue up the logical tree.) If the root of the logical tree is reached and the resource has not been resolved, the application-level resource dictionary will be searched. If still unresolved and a dynamic resource reference was used (or a static reference was deferred), then the theme resources will be checked.
Resources can also be retrieved in code by using the FindResource() method on a framework element. The resolution process is very much the same as with dynamic references.
Resource Considerations for Custom Controls
There are special considerations around resources when writing custom control libraries. My focus in this post is purely on managing application-level resources in a hosted interop scenario. For anyone writing a control library, I would recommend that you check out the following post in the WPF SDK blog:
Using Shared Resources in a Controls Library.
Application-Level Resources in a WPF Application
When building a typical WPF application, the MSBuild project file contains a project element named ApplicationDefinition. This element identifies a XAML file whose root descends from the Application class. So for a C# project, the Application class files would appear as follows in the .csproj file.
<ApplicationDefinition Include=”App.xaml” />
<Compile Include=”App.xaml.cs”>
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
MSBuild now knows that this class represents the entry point for the WPF application, so it auto-generates a file named App.g.cs that contains an entry point, as follows:
[System.STAThreadAttribute()]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public static void Main() {
WindowsApplication1.App app = new WindowsApplication1.App();
app.InitializeComponent();
app.Run();
}
This is the code that instantiates the Application class in a typical WPF application.
As mentioned earlier, the Application class contains a Resources property which identifies the ResourceDictionary where application-level resources reside. A typical ApplicationDefinition file was presented in the introduction section above.
Note that there can be individual resources in the Application’s Resources collection as well as additional merged resource dictionaries. All such resources are available at the application level, and thus, can be referenced freely throughout the application. This provides an elegant mechanism for theming the application, as well as for sharing common resources among different pages, windows, user controls, etc.
Providing Application-Level Resources when WPF is Hosted
When WPF is hosted inside a managed application framework like Windows Forms or in an unmanaged framework like MFC or pure Win32, this elegance provided by application-level resources is lost because WPF’s Application object does not even get created. (Recall that it is the auto-generated code that actually creates the Application instance.) As such, resource resolution occurs only within the element tree and at the theme level.
The good news is that there are several ways to effectively bring back the benefits of application-level resources in these hosted interop scenarios…
Create an Application Instance and Add Resources in Code
The most obvious approach is to simply create an instance of the Application class. Since the Application class is a singleton, you can simply instantiate an instance of the class and then you have access to it throughout your app. Of course, at that point, its Resources collection is empty, so you will probably want to add some resources. Since it is more convenient to declare resources in markup, I typically define my resources in a ResourceDictionary and then merge them into the Resources collection in my Application object.
Below is a very simple function that will create the Application object if it does not exist and then load some resources:
public static void EnsureApplicationResources() { if (Application.Current == null) { // create the Application object new Application(); // merge in your application resources Application.Current.Resources.MergedDictionaries.Add( Application.LoadComponent( new Uri("MyLibrary;component/Resources/MyResourceDictionary.xaml", UriKind.Relative)) as ResourceDictionary); } }
Now you just need to make sure that you call this function prior to parsing any XAML files that contain static resource references to application-level resources. To do this, simply add a call to the above function in the constructor of your markup-based classes before any call to InitializeComponent():
public Page1() { EnsureApplicationResources(); InitializeComponent(); }
Voîla! You now have application-level resource resolution in your hosted scenario.
There are a couple of things worth pointing out here. First, in this scenario, we are only using the Application object for resource resolution. You would not want to call the Application’s Run() method in the hosted scenario, since that would start a WPF dispatcher. In our scenario, the hosting technology is responsible for dispatching Windows messages. (The exception might be if the host was a Win32 console app, in which case you would need to supply a message pump for WPF.)
Another thing to keep in mind is that the Application singleton will remain alive for the remainder of the process lifetime unless you take steps to release it. If your scenario only calls for WPF to be used for a finite period of time during application execution, you should call the Application’s Shutdown() method when you no longer need it. In a non-hosted WPF application, this would actually shut down the application by shutting down the dispatcher. In our hosted scenario, it will simply release the rooted reference to the singleton. After calling Shutdown(), the static Application.Current property will once again return null. At this point, the object should be available for garbage collection.
Define the Application Class in XAML and Create It on the Fly
The above approach is nifty, but it requires us to do the work of adding and merging resources in code. This is great if you want dynamic control over exactly which resources are added. But if your scenario always calls for the same application-level resources, wouldn’t it be easier to just define those in markup the same way you would for a native WPF application?
Good news… You can! You just need to make a couple of small changes to the MSBuild project file and the code-behind for your Application class.
First, we do not want MSBuild to generate an application entry point for our Application class. So instead of declaring the App.xaml file as an ApplicationDefinition element in the project file, we need to declare it as a Page element:
<Page Include="App.xaml" /> <Compile Include="App.xaml.cs"> <DependentUpon>App.xaml</DependentUpon> <SubType>Code</SubType> </Compile>
Next, we need to make sure that our App.xaml markup is parsed. Typically, this is done as part of the entry point function (which we just eliminated). Instead, we can simply define a constructor for the Application class and call InitializeComponent directly:
public App() { InitializeComponent(); }
Now all our resources and merged dictionaries can be declared in App.xaml and our static function to load the Application instance can be as simple as this:
public static void EnsureApplicationResources() { if (Application.Current == null) { // create the Application object new App(); } }
Manage a Collection of Resource Dictionaries in Code and Merge them at the Element Level
The final approach I’ll discuss for managing application resources in a hosted scenario involves programmatically managing a collection of resource dictionaries. In this scenario, we do not leverage an Application object at all. Instead, we dynamically load each ResourceDictionary at runtime and selectively merge it into pages or windows or specific elements, as necessary.
Clearly, this puts more responsibility on the developer for ensuring that the proper resources are merged at the proper locations. But it has benefits too, such as better scoping of resources and not having to track the lifetime of the Application object.
When using this approach, the trick to ensuring that application resources are truly shared across element trees is to only create a single instance of each resource dictionary. This can easily be accommodated by leveraging a static dictionary of dictionaries:
private static Dictionary<string, ResourceDictionary> _resourceDictionaries = new Dictionary<string, ResourceDictionary>();
Now each dictionary can be referred to using a simple name, such as “ApplicationBrushes”. A static utility function can be used to retrieve the resource dictionary by name. If the dictionary is not loaded, the function can automatically load it:
public static ResourceDictionary GetResourceDictionary(string dictionaryName) { if (!_resourceDictionaries.ContainsKey(dictionaryName)) { _resourceDictionaries[dictionaryName] = Application.LoadComponent( new Uri("MyLibrary;component/Resources/" + dictionaryName + ".xaml", UriKind.Relative)) as ResourceDictionary; } return _resourceDictionaries[dictionaryName]; }
And to make this solution play nicely in the WPF world, we should allow dictionaries to be merged declaratively in our markup files. One way to do this is to leverage an attached property. Suppose we define a static class called SharedResources and in that class we define a string property called MergedDictionaries. This would allow us to merge in shared resource dictionaries to the Resources collection of any framework element, by simply doing this:
<Grid dw:SharedResources.MergedDictionaries="ApplicationBrushes;ButtonStyles"> . . . </Grid>
As you can see, my MergedDictionaries property allows for a semicolon-delimited list of resource dictionaries that should be merged into the Resources collection of the Grid.
The only thing left to do now is actually implement the SharedResources class and the MergedDictionaries attached property. Here is that class in its entirety with a few bonus refinements:
using System; using System.Collections.Generic; using System.Text; using System.Windows; using System.Reflection; namespace DrWPF.Windows { public static class SharedResources { #region MergedDictionaries public static readonly DependencyProperty MergedDictionariesProperty = DependencyProperty.RegisterAttached("MergedDictionaries", typeof(string), typeof(SharedResources), new FrameworkPropertyMetadata((string)null, new PropertyChangedCallback(OnMergedDictionariesChanged))); public static string GetMergedDictionaries(DependencyObject d) { return (string)d.GetValue(MergedDictionariesProperty); } public static void SetMergedDictionaries(DependencyObject d, string value) { d.SetValue(MergedDictionariesProperty, value); } private static void OnMergedDictionariesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (!string.IsNullOrEmpty(e.NewValue as string)) { foreach (string dictionaryName in (e.NewValue as string).Split(';')) { ResourceDictionary dictionary = GetResourceDictionary(dictionaryName); if (dictionary != null) { if (d is FrameworkElement) { (d as FrameworkElement).Resources .MergedDictionaries.Add(dictionary); } else if (d is FrameworkContentElement) { (d as FrameworkContentElement).Resources .MergedDictionaries.Add(dictionary); } } } } } #endregion private static ResourceDictionary GetResourceDictionary(string dictionaryName) { ResourceDictionary result = null; if (_sharedDictionaries.ContainsKey(dictionaryName)) { result = _sharedDictionaries[dictionaryName].Target; } if (result == null) { string assemblyName = System.IO.Path.GetFileNameWithoutExtension( Assembly.GetExecutingAssembly().ManifestModule.Name); result = Application.LoadComponent(new Uri(assemblyName + ";component/Resources/" + dictionaryName + ".xaml", UriKind.Relative)) as ResourceDictionary; _sharedDictionaries[dictionaryName] = new WeakReference(result); } return result; } private static Dictionary<string, WeakReference> _sharedDictionaries = new Dictionary<string, WeakReference>(); } }
Notice that in this implementation, instead of keeping a dictionary of dictionaries, I’m keeping a dictionary of weak references to dictionaries. This ensures that my static class does not keep any resource dictionary in memory when it is no longer in use. (The class could certainly be augmented to provide a mechanism to lock a resource dictionary in memory for times when you want to persist resources across application lifetime. In the name of simplicity, I’ll leave that as an exercise for the reader.)
So there you have a few options for dealing with application-level resources while running hosted. Hope it helps!
Best regards,
Dr. WPF
Just what the dr ordered. Thank you! I’m wondering why GetResourceDictionary was changed to private in the very last example?
Also, could you show an example of declaritively setting the page resource. I can get it dynamically but declaritively no go…
Thanks.
Hey jc,
In the last example, I was taking the GetResourceDictionary() routine to the next level where it would no longer be necessary to call it directly. Instead, it becomes a utility method to support the attached property. I can certainly see an argument for keeping it available (either internal or public), but my idea was that it would be easier to simply set the attached property on an element (whether in code or markup) and let it take care of merging the dictionaries.
I’m not sure I understand your question regarding declaratively setting a page resource. In the described example, there would be two resource dictionaries (ApplicationBrushes.xaml and ButtonStyles.xaml) that would be merged on a Grid element by declaratively setting the attached MergedDictionaries property on the Grid. The same method could be used on any framework element (Page, Grid, etc).
Cheers,
-dw
Thanks for the informative article. It is a good guideline when creating projects which are based on WinForms but need some WPF controls also.
Philipp Post
Hello Dr.
I have implemented above approach for my application but I see that it leads to memory leak. On running memory profiler I found that _inheritanceContext member of static ResourceDictionary is refering to My WPF Control for which I set the theme using attached property. Can you please help me with this?
Hi Naveen,
Are you clearing the value of the MergedDictionaries attached property on your control prior to your object going out of scope? MyControl.ClearValue(…); This should release the inheritance context reference.
Thanks for this article. In my post I describe how modifications within the application wide resource dictinonary are propacated correctly when WPF is hosted in a Win32 environment.
Thanks
Tschaena
In my custom resource helper class I instantiate a ResourceDictionary variable and try to set its Source with a relative Pack Uri(“/;component/subfolder/res.xaml”).
Case 1: When I run my WPF app, it calls the helper, which parses the Pack Uri and sets the ResourceDictionary.set_Source perfectly.
Case 2: When I run the ResourceHelpers’ NUNIT test in nunit console application, the code ResourceDictionary.set_Source fails with an exception saying incorrect prefix for the Uri. The exception stacktrace shows that it fails in constructing the WPFWebRequest for the PackUri that I passed.
Case 3: When I run the above mentioned test after running a test which instantiates a WPF component(inside a STA thread), then the PackUri parsing and setting of the ResourceDictionary’s Source works fine.
I could not figure out the reason for this. But I solved my problem by loading the XAML in my ResourceHelper class by using Application.LoadComponent(), as said in this article. It works fine for all the above cases(1,2,3).
note: res.xaml has BuildAction as Page.
Could you explain the case 2 and case 3.
Hi ALX,
Application.LoadComponent() performs all of the work necessary to prepare the XAML/BAML parser to load the component at the given location. It is definitely the best way to load your resource dictionary.
Without debugging it, I couldn’t say exactly what is failing in your Case 2, or why it works in Case 3, but it is almost surely that something in the parser is not initialized. The Case 3 path probably just coincidentally causes that thing to be initialized.
Regardless, you should be safe if you stick with LoadComponent(). 🙂
Cheers,
-dw
Hi Dr. Wpf,
I’ve used your solution of EnsureApplicationResources(), and it works fine the first time.
my entry point looks like this
void StartWpfWindow(IntPtr parentHwnd)
{
if (Application.Current == null)
{
// create the Application object
// Application is a singleton
new Application();
// merge in your application resources
Application.Current.Resources.MergedDictionaries.Add(
Application.LoadComponent(
new Uri(styleXamlPath,
UriKind.Relative)) as ResourceDictionary);
}
MyWpfWindow wnd = new MyWpfWindow();
WindowInteropHelper helper = new WindowInteropHelper(wnd);
helper.Owner = parentHWnd;
wnd.ShowDialog();
Application.Current.Shutdown();
}
However if I call my wpf assembly again, Application.Current is null and when I call new Application, I get the following exception:
“Cannot create more than one System.Windows.Application instance in the same AppDomain.;
Hi Colin,
Sorry for the late reply. Do you have a simple repro for this issue? I’d like to investigate why the framework is maintaining a reference to the original Application instance. Please feel free to send me something to my ask(at)drwpf(dot)com address.
Thanks,
-dw
Hi Dr. WPF,
I am new to WPF and Silverlight. I know you are a doctor who specializes in WPF but I am hoping that you may have run across a few Silverlight courses during your studies. The Application.LoadComponent works a bit differently in Silverlight and I cannot seem to come up with a proper solution.
Thanks for your help,
Al
Hi Al,
Silverlight is pretty much always hosted. Is there a particular hosting scenario you are trying to conquer where you are having trouble with resource resolution?
Cheers,
-dw
Hey Doc,
In regards to Collin’s post… it happens to me when using VSTO and creating an Outlook addin.
Michael
This is very handy, one question (maybe this has been mentioned?)
In your “GetResourceDictionary” method…
You basically set result = null, then if you can’t find a dictionary in the collection with the parameter’s name, you create one.
What about the “else” condition where you DO already have it in the collection?
Your method just returns null. Has nobody had this problem, or am I missing something?
Shouldn’t there be something like this in there?
if (_sharedDictionaries.ContainsKey(dictionaryName) && _sharedDictionaries[dictionaryName].Target != null)
{
result = (ResourceDictionary)_sharedDictionaries[dictionaryName].Target;
}
return result;
Please let me know if I did something wrong… thanks.
Wow! Good catch, Michael K! I’m surprised no one else has reported that. It was definitely a bug.
I updated the GetResourceDictionary() method with something that should work much better. Thanks for the heads up! 🙂
Cheers,
-dw
Thanks for the info. I found that the EnsureApplicationResources() method worked for me (WPF component hosted in MMC); however, the lifetime of the Application object is flaky. I think it gets destroyed as soon as I open a WPF “Window” proper, and then close it. The result was that the entire MMC window closed with no feedback – not even a caught exception under the debugger.
I was able to fix this by doing:
new Application { ShutdownMode = ShutdownMode.OnExplicitShutdown };
Then, when my snap-in is shutting down I explicitly call Application.Current.Shutdown().
I think this might also answer Colin’s problem. It’s worth a try anyway.
Good call, Tom! Yes, if you have windows coming and going, then the app’s shutdown mode is very important in the hosted scenario, since the Application object does not necessarily know about all WPF windows.
Thanks for posting the tip! 😀
[…] Managing Application Resources when WPF is Hosted « Dr. WPF(tags: wpf resources runtime) […]
Thanks Doc & thanks to Tom Kludy as well, that extra tidbit was important to me, since I’m hosting WPF inside Word via VSTO and I had windows coming and going. It fixed the “The Application object is being shut down” errors I was getting the second time I tried to open a window.
Thanks for this, this is really handy. Is there a good way to load code on startup for a non-startup assembly? Say you refer to an assembly, and you want to it run a chunk of code as soon as it is loaded… is this possible? I haven’t found the right hook to do this.