Dynamic DataTemplates in WPF

A while back, I had to do some tricky stuff with WPF. The WPF application need to have a new data type deployed to it on the fly, and then have a set of dynamic data templates deployed to the same application for that new data type. The first pass I made to accomplish this was to make myself an attached property and markup extension to funnel information into a singleton object I would use to manage all of the dynamic styles. Let me expand a little more on my design choice before going into the details.

First, I wanted to have something be in charge of managing all of my data templates. This needed to be the keeper of everything that is styles. This class should be in charge of registration of styles, as well as handing these styles out when they are asked for. Second, I would need to come up with some way of uniquely identifying these data templates, or create a key if you will. After all, we can't have duplicate templates for whatever reason. Lastly, I need some way to give all of this information to WPF so I could leverage it in my XAML. My markup would need to be able to bind to this information so it can be resolved during runtime.

So, like I was saying, my first pass involved using a markup extension in some XAML resource dictionary that would be dynamically merged into the main resource dictionary. This was mostly working fine, but I had this syntax that was bothering me quite a bit. What I essentially had was a attached property referencing my custom markup extension. The thing that got annoying was WPF was requiring me to fill in x:Key for the DataTemplate anyway, even though I wasn't using it. What was happening was my x:Key value was turning out to be the textual representation of my custom markup value. That was dumb to me because I was passing the same information twice. I tried putting my markup extension into the x:Key value, but WPF kept barfing at me when I did this. I stumbled onto this gem, which should have been much easier to find.  My very own custom DataTemplateKey!!

Lets start with the new key object I created to be my unique value for each DataTemplate:


A quick summary about this.  I have a name value that is a string and a instanceType value that is also a string.  This should sound very familiar to you if you have used WPF.  I have made sure to override the standard System.Object overrides for equality.  Next, our markup extension:


Notice the base class of DataTemplateKey.  This allows us to place our markup in the x:Key field of the XAML.  The XAML markup will map to our key now, so we have the same fields here as strings, name and instanceType.  The really important part here is the override of ProvideValue that will get called when the XAML if parsed.  We are going to use our new key class to create a key.  Then, we pass the key to the DynamicTemplateManager.  Here is the code listing for that class:


I left out some of what I consider to be the fluff of this class for readability.  First thing to notice is the DependencyObject as the base class.  This helps to allow us to use our new template manager in the XAML, so we could bind to it if we wanted.  Cool stuff of note are the two indexers that should aid in the binding process, particularly the string, string indexer.  The key to the whole class is the Add method and the different dictionaries declared locally.  The dictionaries are going to keep all of my templates keys based on how I register them.  We have one each for typed templates, named templates, and typed and named templates.  Now, as long as our dynamic XAML is merged in with our visual tree, and using our keys, we should be able to find our DataTemplate using a App.Current.TryFindResource(object) passing the DynamicTemplateKey as the parameter.

You can download the source code for this here.  I haven’t posted any examples in it of how to use the key in XAML, but if you are familiar with DataTemplates and MarkupExtensions, it shouldn’t be a problem for you.  If I get a fair about of interest in using this in an example, I may post a part 2 to this post.  Please feel free to let me know if you would like to see an example.

Share this post!

0 comments:

Post a Comment