Mike Hillberg has some great observations about WPF application architecture as it pertains to model interaction in his “Model See Model Do” post. I am very much in agreement with Mike on this subject.
And let me also say that I’m very happy to see Mike posting a bit more on WPF recently. 🙂
There is another thing definitely worth highlighting in Mike’s latest post… In his code sample, he uses a little trick to ensure that bindings on his command and argument objects resolve correctly. Namely, he derives them from Freezable:
public class MethodArgument
: Freezable // Enable ElementName and DataContext bindings
Normally, ElementName and DataContext bindings are resolved based on the target dependency object’s position within the element tree (or the namescope to which the target dependency object belongs). But in this case, the target dependency object is not actually in the tree. Instead, it is just a property value on another object. That other object may or may not be in the tree.
The reason the Freezable trick works is because a Freezable object has its own notion of “inheritance context”. When the property engine sets the effective value of a dependency property, it looks at that new value to determine whether it is a dependency object that would like to be part of a special inheritance tree. A Freezable is one such object that always wants to be in the inheritance tree when not frozen. As such, when the Command property on Button is set to a Freezable in Mike’s example (below), the framework adds the Button itself as the inheritance context of the Freezable.
<Button Content="Rename"> <Button.Command> <mc:MethodCommand MethodName="Rename"> <mc:MethodArgument Value="{Binding Text, ElementName=_renameTextBox}" /> </mc:MethodCommand> </Button.Command> </Button>
The MethodCommand object above will now have the Button as its inheritance context. As such, even though MethodCommand is not a FrameworkElement with a tree-inherited DataContext property, it still effectively inherits the data context of the Button. A binding on any property of the MethodCommand object will use its inheritance context to arrive at an implicit binding source (which will be the DataContext of the Button in this case).
The same construct is used to pass the inheritance context from a MethodCommand to its MethodArgument objects, so that their bound properties, too, can be resolved.
(Note that a Freezable can also have more than one inheritance context, but I’ll leave the discussion of how multiple inheritance contexts are handled for a future post.)
In addition to the above scenario (where a freezable is set as a dependency property value on a dependency object), it is this enhanced notion of an inheritance tree and inheritance context that allows bindings on brushes, animations, and other freezable objects to work when those objects are placed within a resource dictionary.
Mike’s approach is definitely a cool trick and I’ve used it myself on occasion. Of course, there are scenarios where inheriting from Freezable is not really an option. In such situations, the hack I find most useful for enabling bindings on non-freezable objects is to artificially add such objects to the logical tree. But I would love to see Microsoft publicly expose the ability to control an object’s inheritance context so that all these hacks could just go away. (Hint, hint! ;))
Enhancing Developer/Designer Productivity
Monday, October 8th, 2007“Joe” added the following comment to my earlier post on WPF project structure:
I would be interested to know how developers tackle the Blend issue. I’ve hit problems when most of the visuals are embedded in Data Templates and you only see the final product when real data is populated into the ItemsControls. Are developer teams using canned data just to edit the visuals?
The answer to that question for most of the projects I’ve worked on is definitely “yes”. Designers are most effective when they can edit templates directly. To do this in Blend, you often have to simulate the real data by using fake data.
Laurent Bugnion just posted a nice screencast on a very structured approach to enhancing designer/developer productivity in WPF. This approach is built around the concept that there are three distinct personas involved in the development process: designer, developer, and integrator (the ever-elusive “devigner” who understands both worlds and can work in the middle to integrate the code and the design).
And in this earlier blog post, Laurent provides an article demonstrating how one might provide “canned data” in design mode to accomodate the editing of templates in Blend.
Can I bind my ItemsControl to a dictionary?
Sunday, September 16th, 2007I’ve seen a number of forum posts lately expressing a desire for an observable dictionary. Here are links to a couple of them:
Thread 1: Observable Dictionary, problem with Remove
Thread 2: Bind observable dictionary
As promised in my response to the latter thread, I am now providing a sample demonstrating how one might implement an observable dictionary. You can download the sample here.
The Observable Dictionary Sample
In this sample, I demonstrate how to bind to a dictionary of button styles. The styles are sorted based on their Key values in the observable dictionary. (Clearly, this should be treated as a nonsensical illustration for demonstration purposes only.)
On the left side of the window is a ListView that is bound to the observable dictionary. If you click an odd-indexed button in the ListView, its corresponding entry is removed from the dictionary. If you click an even-indexed button, its entry is duplicated in the dictionary.
On the right side of the window is a ComboBox whose items are bound to the same dictionary. Beneath the ComboBox is a Button whose style is bound to the selected value of the ComboBox. If you click this button, the dictionary will be cleared and reloaded.
As you click around, you will notice that the bound controls respond appropriately to any changes in the observable dictionary.
So why would someone want to do this?
Dictionaries are easy to work with in code. Perhaps you’ve already written an application that leverages a dictionary to store and retrieve in-memory data. You may now want to provide a view of the dictionary entries in your user interface.
Unfortunately, to provide a dynamic view of your dictionary data, you would need to do a lot of extra work. Namely, you would need to write code to synchronize some observable collection with your dictionary whenever you modify it.
Wouldn’t it be nice if the dictionary, itself, were observable?
The Observable Dictionary Class
What we clearly need is an “observable” dictionary class. You will find an example of such a class in the ObservableDictionary.cs file in the provided sample. What does it mean for a dictionary to be observable? In WPF, an observable class is simply a collection class that provides change notifications whenever its collection changes. It does this by implementing the INotifyPropertyChanged and INotifyCollectionChanged interfaces. This allows it to serve as the “ItemsSource” of a collection control (like a ListBox, ComboBox, or any other ItemsControl). These controls know how to monitor the collection for changes.
For a detailed explanation of how binding to a collection works, see the MSDN documentation. Here is a good starting point.
So how do you implement an observable dictionary?
Dictionaries basically work by aggregating an internal collection of key-value pairs. People often start by trying to derive a class from Dictionary<TKey, TValue> or by trying to implement IDictionary<TKey, TValue> in a class that aggregates a dictionary. The idea is that they could then add the requisite INotifyPropertyChanged and INotifyCollectionChanged interfaces and have an observable dictionary.
There’s a major problem with this approach. Observable collections are indexed by integer. In order to fire the necessary collection change notifications, you must know the index of an entry when it changes. Unfortunately, none of the interfaces exposed by the Dictionary<TKey, TValue> class are indexed by integer. And if you derive directly from Dictionary<TKey, TValue>, you do not have access to the underlying collection. As a result, an attempt to create an observable dictionary by deriving from or aggregating a dictionary won’t work.
To truly create an observable dictionary, you need to aggregate your own collection (usually of type KeyedCollection<TKey, TValue>). Then you must implement a whole slew of interfaces on top of the collection, as shown in the following class declaration:
public class ObservableDictionary <TKey, TValue> :
IDictionary<TKey, TValue>,
ICollection<KeyValuePair<TKey, TValue>>,
IEnumerable<KeyValuePair<TKey, TValue>>,
IDictionary,
ICollection,
IEnumerable,
ISerializable,
IDeserializationCallback,
INotifyCollectionChanged,
INotifyPropertyChanged
By implementing all of the above interfaces, you ensure that your dictionary class can be used interchangeably with the CLR’s Dictionary class. You should only need to change the declaration from Dictionary<TKey, TValue> to ObservableDictionary<TKey, TValue> in your code.
Pros and Cons
The benefit to using an observable dictionary, of course, is that the dictionary can serve as the ItemsSource for a databound control and you can still access the dictionary in code the same way you access any other dictionary. It is truly an indexed dictionary of objects.
There are certainly some limitations inherent in the very idea of making a dictionary observable. Dictionaries are built for speed. When you impose the behaviors of an observable collection on a dictionary so that the framework can bind to it, you add overhead.
Also, a dictionary exposes its Values and Keys collections through separate properties of the same name. These collections are of types Dictionary<TKey, TValue>.ValueCollection and Dictionary<TKey, TValue>.KeyCollection, respectively. These CLR-defined collections are not observable. As such, you cannot bind to the Values collection or to the Keys collection directly and expect to receive dynamic collection change notifications. You must instead bind directly to the observable dictionary.
The Observable Sorted Dictionary Class
Another thing to note is that a dictionary doesn’t typically store its data in a deterministic order. When binding to an observable dictionary, you cannot simply apply a sort order via a CollectionView because the exposed interfaces do not support sorting. For this reason, I include an ObservableSortedDictionary class in the attached sample.
Binding to an Observable Dictionary
When you bind to an observable dictionary, you are really binding to a collection of KeyValuePair objects. A KeyValuePair is an object which makes the entry’s key available via an appropriately named Key property and its value available via a Value property. Your item templates must take this into consideration and provide the appropriate binding paths. The provided sample illustrates how to do this.
All the Standard Caveats Apply
As always, this sample is provided “as is”. It has not been heavily tested and there are probably lots of improvements that could be made. Use it and modify it as you see fit. Let me know how it works for you, what improvements you make, what bugs you find, etc.
Cheers,
Dr. WPF