Archive for the ‘WPF’ Category

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

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

Support Your Local Pub

Wednesday, August 29th, 2007

Recently, one of my peers informed me that due to my lack of participation in the WPF community, I’m just not a good citizen.  I told him to go to h… well…  you get the gist.

I was feeling a twinge of guilt about this, so I decided to look up my most recent posts in the WPF… er… uh… “Avalon” community forums.  (Well that can’t be good.)  Upon seeing the timestamps on those posts, I was feeling a slightly larger twinge of guilt.  Then I looked at the actual content…  WOW! 

How did we survive in a world without Grid?  Was there really once a native element called FlowPanel?  And the binding syntax… that’s just wrong!  Okay, clearly it’s been too long and I might just be a bad citizen.

Sidenote:  I was tempted to include some links to those posts, but they are all under the name I was using prior to joining the witness protection plan.  So in the interest of protecting my family, who desperately would like to distance themselves from my geekiness, I’m leaving those links out.

To ease my conscience, I’ve been hanging out in the WPF MSDN Forum for the last few days.  I’ve got to admit… this is a pretty cool place!  I plan to pop in here more frequently.  It’s amazing how much the community has grown and what a wealth of knowledge is available now.  And the volume of activity completely blew me away.  If you haven’t been there lately, stop being a bad citizen and check it out!

Hosting Office in a WPF Application

Friday, August 24th, 2007

note 

Updated on December 17, 2009

The approach described in this article for hosting office documents in WPF is no longer supported.  Microsoft has recently pulled the DSO Framer control from its knowledge base.  🙁

Please contact Microsoft Developer Support directly if you have questions regarding this decision.

 If a new supported solution for hosting Microsoft Office applications within WPF becomes available, I will try to post a sample.

Cheers,
Dr. WPF


Dear Dr. WPF,

Is it possible to host Microsoft Excel inside of a WPF application? Do you have any sample code?

Sincerely,
Rob
 


Hi Rob,

It’s certainly possible to host a Microsoft Office application inside of a WPF application. And just to prove it, I’m writing this entire post inside of Microsoft Word while it’s being hosted inside my WPF application.

WPF Hosting WordFeel free to download the code for this sample. This sample will work for hosting Word, Excel, PowerPoint, or Visio documents. It should host Project documents also, but I don’t have Project, so I couldn’t verify this. And I should note that hosting Visio 2007 documents proved to be very flaky. The Visio host crashed more often than not. The other hosts seemed pretty stable.

You will need to install the DSO Framer control prior to running the sample. More on that below…

So yes, it’s possible to host an Office application, but that doesn’t necessarily mean it’s easy! There are definitely a lot of caveats, disclaimers, qualifiers, stipulations, and limitations (yep, even the thesaurus works in the hosted scenario!) when hosting any Win32-based window (a.k.a., an HWND) within a WPF app. Most of these are documented in the SDK in topics like WPF Interoperation: ”Airspace” and Window Regions Overview and Hosting a Microsoft Win32 Window in WPF. In the latter article, special attention should be given to the sections entitled “Notable differences in output behavior” and “Notable differences in input behavior”.

Hosted Office applications come with a whole set of their own challenges (keeping the document focused, keeping application menus in sync with document menus, etc). If you go down the path of hosting an Office app, you should expect some technical challenges and a potential steep learning curve, especially if you’re considering office automation.

There are code samples in the SDK that demonstrate how to host an ActiveX control inside your WPF application. So if you can find a simple ActiveX wrapper for your Office application, then you’re all set, right?

Well, unfortunately it’s not that easy when it comes to hosting Office. An Office application, like Excel, has much larger requirements for its host container. The host must be an Active Document Container. This container implements a number of COM interfaces above and beyond those found in a simple ActiveX host.

There are a couple of Active Document Containers readily available on most Windows machines: 

1. Internet Explorer

2. the Windows Forms WebBrowser control

The simplest approach to hosting an Office application inside a managed application involves hosting the Windows Forms WebBrowser control and pointing it at an Office document. If all you care about is simple hosting, this approach might work for you.

SIDEBAR: For the record, I should point out that there is also an unmanaged WebBrowser control (shdocvw.dll) that ships as part of Internet Explorer. This control can be hosted in an unmanaged app (or even in a managed app using the instructions in this article, but why would you do that when there’s already a managed control?). Indeed, the Windows Forms WebBrowser control is just a managed wrapper around the Internet Explorer WebBrowser control. As such, Internet Explorer must be installed for any solution that involves either WebBrowser control.

Usually, however, if you are hosting something like Excel, you need to automate the document (to load, save, or print it, invoke automation commands, etc). The WebBrowser control does not give you much access to the document-related automation classes. (For information on the Office automation classes, check out the vast Office Development documentation in the SDK.) For this level of control, you need a better Active Document Container. Unfortunately, Microsoft has not released any such “supported” container. It would be great if they could put out a managed control that could serve as an Active Document Container. But so far, the only thing they offer is an “unsupported” container in the form of an ActiveX control called DSO Framer control.

The DSO Framer control was produced a few years back by the good folks in Microsoft Developer Support. Although their name says it (“Support”, that is), they don’t do it (“Support”, that is) for this control. The DSO Framer control (along with its source code… yes, you get the full source) is provided “as is”. Microsoft doesn’t support it and Dr. WPF doesn’t support it either… However, we both use it!

My sample of WPF hosting Word (illustrated above and available for download) is indeed built using the DSO Framer control. It is an extremely simple implementation of a WPF application hosting an ActiveX control. In this case, that ActiveX control just happens to be an Active Document Container.

NOTE: I could not get the most recent version of the DSO Framer control (compiled as a 32-bit control) to run on my 64-bit Vista box. It runs well on my 32-bit Vista installation. On my x64 machine, the application complains that the control is not registered, even though I can verify and instantiate an instance just fine in OleView. Not sure if this is a problem with the control or a configuration problem on my machine. If others encounter the same problem, I’d love to hear about it. Maybe someone in Microsoft Developer Support could try to reproduce this failure and look into a fix (hint, hint)… Oh yeah… it’s not a supported control. Maybe if I say “pretty please”.

FIX: Several people have advised that compiling the WPF application to specifically target the x86 platform (rather than “Any CPU”) fixes the above load issue on x64.  Thanks to all for this fix!  😀

Anyway, I hope you find this information and sample helpful!

Best regards,
Dr. WPF

Can my value converter access the target of the binding?

Saturday, August 18th, 2007

Dear Dr. WPF,

In my application, I’m using a value converter to convert a GUID to a static resource.  The GUID is accessible in my DataTemplate through a binding like this:

<DataTemplate>
  <Grid Height="Auto" Width="Auto">
    <TextBlock Text="{Binding Path=ID}" />
  </Grid>
</DataTemplate>

I would really like to use the GUID in a more dynamic way as a key into a resource dictionary. I imagine it would look something like this (although obviously this won’t work): 

<DataTemplate>
  <Grid Height="Auto" Width="Auto">
    <ContentControl 
        Content="{StaticResource {Binding Path=ID}}" />
  </Grid>
</DataTemplate>

I thought I might be able to use a binding along with a value converter that uses FindResource() to look up the static resource. Unfortunately, my value converter does not receive a reference to the object on which the binding is set. It only gets the bound value (the GUID) and the type of the target dependency property. In order to call FindResource(), I need a reference to the actual target dependency object.

Is there an easy way to do this in WPF?

Thanks for any help you can provide!

Sincerely,
Jim
 


Hi Jim,

Yes, it can be frustrating that your value converter does not receive a reference to the target dependency object for the binding. Value converters were designed to be more generic in nature, allowing them to be used in scenarios that might not involve bindings. As such, they have no knowledge of the binding itself or the object on which it is set. That said, there are actually many cases where a value converter might desire this kind of contextual information. 

Your scenario is a prime candidate for a multibinding and multivalue converter. With a multibinding, you can actually supply your own reference to the target dependency object using one of the bindings, as follows:

<DataTemplate>
  <Grid>
    <ContentControl>
      <ContentControl.Content>
        <MultiBinding Converter="{StaticResource MyConverter}">
          <MultiBinding.Bindings>
            <Binding RelativeSource="{RelativeSource Self}" />
            <Binding Path="ID" />
          </MultiBinding.Bindings>
        </MultiBinding>
      </ContentControl.Content>
    </ContentControl>
  </Grid>
</DataTemplate>

 

In this case, the converter class must implement the IMultiValueConverter interface so that it can be used with the multibinding. Since we have conveniently passed in a Self reference as the first binding, we now have a reference to the target dependency object in our converter. The converter’s Convert method might look something like the following:

public object Convert(object[] values, Type targetType, 
    object parameter, CultureInfo culture)
{
  FrameworkElement targetObject = values[0] as FrameworkElement;
  if (targetObject == null)
  {
    return DependencyProperty.UnsetValue;
  }
  return targetObject.TryFindResource(values[1]);
}

 

I hope this helps!

Best regards,
Dr. WPF

The Doctor Is In

Monday, August 13th, 2007

Welcome to the online office of Dr. WPF.  This is my obligatory “Hello World” post.

I’ve managed (quite deliberately) to avoid the whole world of RSS for the past several years, as I really haven’t had much to say that I would deem especially blogworthy.  But lately, I’m spending more and more time answering questions about WPF, so it occurs to me that some of my knowledge might actually qualify as marginally interesting to a few of you.

So here goes…

If you have questions about WPF that you think might have broad appeal, please drop me an email and I will do my best to answer them.  If the volume becomes very large, I reserve the right to become very selective.

And thanks in advance for your patience as I learn the ins and outs of this thing we call the blogosphere.  🙂