Archive for September, 2007

Can I bind my ItemsControl to a dictionary?

Sunday, September 16th, 2007

I’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

The Doctor is on a quest for 5… Yes 5 Gold Stars

Tuesday, September 11th, 2007

In an earlier post, I mentioned that I’ve been hanging out in the MSDN WPF Forum lately.  

I was feeling pretty good about my 100th post the other day, and in fact, I was even considering retirement from the forums so I could spend my afternoons playing golf.  (Isn’t that what doctor’s do when they retire?)

Then I noticed something disturbing!  Right there under my name were two little gold (well, yellow really) stars.  For some reason, I had never even noticed the rating system before.  And now, on the crest of my retirement, I discover that I’ve only scored 2 out of a possible 5 stars… clearly there is still much work to be done.

How much?  Well, I did a quick search and found this information on the MSDN recognition system. 

Begin Edit:

Strike that!

Okay, I feel pretty good about earning 2000 points in my first 2 weeks, but come on!  Do I seriously have to earn a million points to retire with 5 stars?  Am I the only one that thinks the cost of that last star is just a little too high?  I figure I can reach 4 stars (15000 points) in about 3 months at my current pace.  But then that last star is going to cost me roughly 19 more years!!  I don’t think so!

Okay, clearly my understanding of how the point system works was drastically off! 🙂

The values in that chart are the upper limit for the star level, not the requirement.  So in order to get my 5 gold stars, I only need to achieve 15000 points.  Much Better! 

Of course, that also means I don’t yet have the 2000 points that I thought I had.  🙁

I discovered that by clicking my name, I can see exactly how many points I have.  Currently, I have 851 recognition points, so I still have a ways to go!  But at least its within reach!  Yep… still a “noob” at this forum thing!  🙂

End Edit

Image Manipulation using WPF Imaging Classes

Saturday, September 8th, 2007

The following question recently appeared in the WPF forum:


Is there posibility of resizing BitmapImage using WPF?

I do not want to resize an Image control. I want to resize image itself so when i convert it to bytes and stores it in database it has desired size.


In my response to that question, I included some sample code demonstrating how you might resize an image by leveraging the BitmapImage class to decode the image to the desired pixel width and height and then save the converted image back to a disk file or store it in a database.

I also mentioned that there are some additional imaging classes that can be leveraged for other common image manipulation tasks.  After receiving a couple of inquiries about these other classes, I decided to expand my sample a little. 

Here is a sample application that demonstrates how to use the CroppedImage and TransformedImage classes.  It also includes the resize code from the earlier sample.

Note that I’ve written this sample as a simple .NET console application.  (This should reinforce the idea that WPF is more than just a “presentation” framework.)  You can pass the app commands like rotate left, rotate right, flip horizontally, flip vertically, and crop square. 

Hope others find this useful.

Cheers,
Dr. WPF

Supplying an Object Reference in the ConstructorParameters Collection of an ObjectDataProvider

Sunday, September 2nd, 2007

Dear Dr. WPF,

I have a .NET 2.0 data collection object that aggregates RSS feeds and maintains the incoming posts in an in-memory collection (as well as saving them to a data store). The class has no associated UI… it just provides the data as well as a few events that can be used to filter (accept/reject) posts as they arrive.  I have used it quite successfully in several different applications.

I recently decided to enhance the class to better support .NET 3.0 scenarios.  As such, the posts are now maintained in an observable collection, which works great for databinding.  But I would also like to support the routed event model and rather than requiring consumers of my object to attach event handlers, like in the 2.0 version, I’d like to have the object raise bubbled events.

This is where the trouble comes…  As mentioned earlier, the control has no knowledge of the UI.  It just knows about the data.  In order to raise routed events, it needs a target element.  To support this, I’ve created a constructor that accepts a UIElement, and if present, I will raise events on that element.  This works fine when I create my data object in code, but I would like to support creating it in XAML using an ObjectDataProvider.

Here is what I would like to do:

<Grid Name="RssGrid">
  <Grid.Resources>
    <ObjectDataProvider x:Key="RssData" 
        ObjectType="{x:Type rss:RssFeeder}">
      <ObjectDataProvider.ConstructorParameters>
        <Binding ElementName="RssGrid" />
      </ObjectDataProvider.ConstructorParameters>
    </ObjectDataProvider>
  </Grid.Resources>
  <ListBox DataSource="{StaticResource RssData}"
      ItemsSource="{Binding Path=RecentPosts}" ... />
</Grid>

But this doesn’t work because bindings can only target dependency properties.  The ConstructorParameters collection is a CLR property.

Is there any way to do this in XAML?

Sincerely,
Marie
 


Hi Marie,

It’s funny how the same question will pop up all at once from several different sources.  Yours is one such example.  I have received variations of this same question from no less than 4 different people within the last month.  It typically takes one of the following forms:

In markup, how do I pass an instance of an object …

1.  in the ConstructorParameters of an ObjectDataProvider?

2.  as the ConverterParameter of a Binding?

3.  as the value of a CLR property (that is not backed by a dependency property)?

And just last week, I saw this version of the same question (very similar to your scenario) in the WPF forum on the MSDN site.  In my response to that post, I said I would blog about an approach that I sometimes use to do this.  I think this solution will work nicely for you also.  You’ll find the promised details below.

Best regards,
Dr. WPF

 

Introducing the ObjectReference Markup Extension

First, let me say that although this solution can be used as an answer to all 3 of the scenarios described above, it’s not always the most appropriate solution.  In this earlier post, I provided a MultiBinding approach that I believe is often a more dynamic answer for question 2.  And question 3 can sometimes be better accommodated by using a one-way-to-source (or two-way) binding on another property wherein the source (the CLR property) essentially becomes the target.  I will likely blog about that approach in a future post.

Enough blather.

So how do you pass an object instance to the ConstructorParameters collection of the ObjectDataProvider?  The short answer is…

It Can’t Be Done

… using the native XAML support in 3.0 or 3.5.  More specifically, unless the object is a resource, there is no way to directly reference it in markup.  If the target property is a dependency property on a dependency object within the visual tree, then a binding can be used to create an indirect reference to the object.  But in all of the cases above, the target is not a dependency property, so this won’t work.

One strength of WPF is that it’s more than just a framework… it’s an extensible “platform”.  So what can we do?  We can extend markup!

A New Markup Extension

To solve the problem at hand, I introduce to you a markup extension I’ve created called ObjectReference.  You can use this extension in your projects by adding this small code file to the project. 

You are certainly already familiar with a number of native WPF markup extensions:  {Binding}, {TemplateBinding}, {StaticResource}, {DynamicResource}, {x:Null}, {x:Static}, {x:Type}, {x:Array}, etc.  Just like all of these classes, the ObjectReference class derives from the MarkupExtension base class and provides extended functionality for XAML-based scenarios. 

Usage in Markup

The ObjectReference extension can be used in markup in two ways:  first as a “declaration” on an object and second as a “reference” to an earlier declaration.  Both of these uses can be seen in the following example:

<Grid xmlns:dw="clr-namespace:DrWPF.Markup"
    dw:ObjectReference.Declaration="{dw:ObjectReference RssGrid}" >
  <Grid.Resources>
    <ObjectDataProvider x:Key="RssData" 
        ObjectType="{x:Type rss:RssFeeder}">
      <ObjectDataProvider.ConstructorParameters>
        <dw:ObjectReference Key="RssGrid" />
      </ObjectDataProvider.ConstructorParameters>
    </ObjectDataProvider>
  </Grid.Resources>
  <ListBox DataSource="{StaticResource RssData}"
      ItemsSource="{Binding Path=RecentPosts}" ... />
</Grid>

Note the use of an attached Declaration property to declare the object reference.  This is one method of declaring a reference on a dependency object.  In this case, a reference is created for the Grid object and it is assigned a Key value using the string “RssGrid”.

Later, the object is referenced in the ConstructorParameters collection by using a second ObjectReference with the same Key value.

If the target object is not a dependency object, you can declare a reference by setting an existing property using the ObjectReference extension.  In this case, you must set the IsDeclaration property to true when creating the ObjectReference, as shown here:

<winforms:MonthCalendar 
    Name="{dw:ObjectReference mc, IsDeclaration=True}" >

Because IsDeclaration is true, the reference is treated as a declaration for the MonthCalendar object.  In this case, the supplied key value of “mc” is passed straight through to the Name property.  It is essentially the same as saying Name=mc, except that it also creates a reference to the object.

Download a Sample

If you’ve examined the code in the sample I posted earlier in my forum response, note that it is slightly different that the version described herein.  I have updated the extension to make it fit for wide consumption and more applicable to other scenarios, such as referencing non-dependency objects.  You can download the updated ObjectReference sample here.

How it works

Let’s take a look at how this ObjectReference markup extension works…

Like any markup extension, our class derives from MarkupExtension and overrides the ProvideValue() method to return a resolved value.  The IServiceProvider parameter supplied to this method provides access to the parser’s context and allows us to know things such as which property the extension is targeting and the exact instance of the object that owns the property.  This is very helpful for our purposes.

If you look at the code in the ProvideValue() function, you’ll see that it first checks to see if we’re creating a declaration or a reference.  If it’s a declaration, then a reference to the target object is added to a static dictionary of weak references using the Key property as the dictionary key for the reference.  In this case, the Key value is returned as the result of the ProvideValue() function.  If the ObjectReference is being used as a reference (rather than a declaration), the ProvideValue() function looks up the supplied Key in the dictionary and returns the object stored earlier.

Sidenote:  Since we are maintaining references in a static dictionary, it is important that we only keep weak references to the objects.  Otherwise, our references would keep the objects alive indefinitely.  We certainly don’t want to leak objects.

Limitations

There are definitely some limitations to be aware of with this approach. 

Parse order matters

First and foremost, this solution is very dependent on the order in which the markup is parsed.  The declaration must be parsed before the reference.  Keep in mind that XAML is parsed from top to bottom.  This is similar to the way static resource references work, but not exactly.  Static resources are resolved based on the tree of elements, whereas, with our extension, it is purely based on parse order.  The reference can appear in another tree entirely and, as long as that tree is parsed first, the reference will resolve.

It’s not a binding

Second, note that the reference is not a binding.  It is resolved exactly once at parse time and it resolves based on the values in the static dictionary at that point in time.  If you change a reference later, it will have no effect on the earlier returned object.

References will be overwritten

Also, note that a reference will be overwritten if another declaration is parsed having the same Key value.  Most of the time, this will be the desired behavior.  For example, if you parse a XAML page that contains a declaration on its root element and references in the same page, you’ll want the references to refer to the declaration for that instance of the page.  There is no way to get at the earlier references after they’ve been replaced.

The ObjectReference class must be in the project

You must include the ObjectReference.cs file in the project.  If you use ObjectReference extensions in loose XAML files, other parsers may not be able to parse the files.  To work around this limitation, you could compile a separate assembly including the extension and include it alongside the loose XAML.  The xmlns namespace mapping in the XAML files would need to reference the assembly containing the ObjectReference class.

The reference dictionary is never compacted

To clean up this extension, I really should periodically walk the dictionary of weak references and remove entries for objects that no longer exist.  So far, I’ve just been too lazy to do that.  You’ll note that I’m providing the ObjectReference.cs file under a BSD open source license, so feel free to make any such improvements that you see fit.  J

Let me know how it works for you!

Please let me know in what creative ways you are able to use this markup extension.

Cheers,
Dr. WPF