What is the difference between… ?
I had a blast at TechEd. After a few years working on WPF, it’s very rewarding to see people’s excitement when they discover all the features we offer. The high point of the conference for me (apart from several detours to the Belgian chocolate fountain, yum…) was Ian Griffiths’ presentation on data binding. If you haven’t seen Ian speak, you’re missing out! His presentation was well prepared, well delivered and technically accurate. I was also very excited to see that the WPF’s labs were incredibly popular, so popular in fact that half way through the conference the number of machines assigned to WPF was doubled.
Now, back to the rainy weather… sigh…
Today I will answer a few simple questions that I get asked repeatedly. There are some concepts in WPF data binding that are similar enough that users become easily confused. If there are other concepts that you think should have made this list, please leave a comment and I’ll cover them in my next post.
What is the difference between CollectionView and CollectionViewSource?
The short answer is that CollectionView is a view and CollectionViewSource is not.
Every time you bind an ItemsControl directly to a collection, we create a view on top of that collection and bind to the view instead. You can think of a view as a list of pointers to the source collection. Views make it possible to perform four operations on bound collections: sorting, filtering, grouping and tracking the current item. Creating an intermediate object to handle these operations may seem like unnecessary overhead, but it’s important to guarantee that the original data remains intact. Imagine the problems that could occur without view objects if two different parts of the UI were bound to the same collection but with different sorting and filtering.
So, what is the type of that view object? At the very minimum, it needs to implement ICollectionView. CollectionView is the base implementation we provide for this interface, and it’s also the view type we create when the source collection implements IEnumerable and nothing else. CollectionView is the base class for two other interesting view classes: BindingListCollectionView, which we create when the source collection implements IBindingList, and ListCollectionView, which is created when the source collection implements IList. I talked about views in a bit more detail in an earlier post.
CollectionViewSource is *not* a view. We designed this class for three reasons:
- We wanted to allow users to create a custom view and be able to tell us to use that view without the use of code (all in markup). I may show how this can be done in a future post (is this a topic of interest?).
- We wanted to allow users to do simple sorting and grouping without using code. You can see a sample with this scenario in this earlier post. - We wanted to have a container for all methods and properties related to view operations. I’m not sure where they lived before we had this class - possibly in BindingOperations - but I do remember realizing that users had a hard time finding them.
CollectionViewSource has a Source property that should be set to the source collection and a read-only View property that returns a handle to the view we create over that collection. If we set the Source property of a Binding to a CollectionViewSource, the binding engine is smart enough to understand that most of the time we really want to bind to the view, so it binds to its View property instead. (If this is not what you want, you can set the BindsDirectlyToSource property of Binding to true.) I believe this is the reason why people tend to think that CollectionViewSource is a view. Also, the name is probably a bit misleading.
In summary, you can think of CollectionViewSource as an intermediate class that has a pointer to the source collection and another one to the corresponding view, and that offers the advantages I mentioned above. A CollectionView is simply the base class for all view types we ship in WPF.
What is the difference between Binding and TemplateBinding?
Binding provides much more flexibility than TemplateBinding, but it’s more costly. TemplateBinding is limited to one scenario but very efficient in what it does.
Everytime you want to bind to a property of an element from within its template, you should consider using a TemplateBinding. For example, consider the following scenario:
<Window x:Class="CommonQuestions.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="CommonQuestions" Height="300" Width="300">
<Window.Resources>
<ControlTemplate TargetType="{x:Type Button}" x:Key="buttonTemplate">
<Border BorderBrush="{TemplateBinding Property=Background}" BorderThickness="3" >
<ContentPresenter Margin="10"/>
</Border>
</ControlTemplate>
</Window.Resources>
<StackPanel Margin="20">
<Button Template="{StaticResource buttonTemplate}" HorizontalAlignment="Center" Background="SteelBlue">Hello</Button>
</StackPanel>
</Window>
In this case, I want the BorderBrush property of Border to be whatever color is specified in the Button’s Background. This is exactly the scenario that TemplateBinding is optimized for. Instead of the TemplateBinding in this snippet, you could use the following Binding: {Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background}. The resulting behavior would be the same, but this is not as efficient, and it’s quite a bit more complex to write, so TemplateBinding is the preferred approach. TemplateBinding also allows you to specify a Converter and a ConverterParameter, which increases the scope of the supported scenarios quite a bit. However, a TemplateBinding can only transfer data in one direction: from the templated parent to the element with the TemplateBinding. If you need to transfer data in the opposite direction or both ways, a Binding with RelativeSource of TemplatedParent is your only option. For example, interaction with a TextBox or Slider within a template will only change a property on the templated parent if you use a two-way Binding.
In summary: if you want a one-way binding from within a template to a property of its templated parent, use TemplateBinding. For all other scenarios, or for extra flexibility in this last scenario, use Binding.
What is the difference between ContentPresenter and ContentControl?
If you look at these two classes in reflector, you will notice the main difference between them: ContentControl derives from Control, and ContentPresenter doesn’t.
ContentControl is a control that knows how to display content. If you’ve been reading my blog, you’re probably familiar with ItemsControl by now, which is a control that knows how to display a collection of data. ContentControl is the equivalent to ItemsControl, but it is used to display non-collections instead. Some classic examples of controls that derive from ContentControl are Button and Label. Its most important property is the Content DependencyProperty, of type object.
ContentPresenter is an element that is useful inside the template of a ContentControl, and is used to specify where you want its content to be placed. For example, in the markup above I placed a ContentPresenter inside the Border because I want the Content of the Button (“Hello”) to appear inside the Border. If you remove the ContentPresenter, you will notice that “Hello” is no longer displayed. If you add elements before or after, you will notice that “Hello” will show up in the location where the ContentPresenter is placed in the layout pass.
The ContentPresenter tag in the markup above is equivalent to the following:
<ContentPresenter Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}" Margin="10"/>
A long time ago, you had to be explicit about where the Content, ContentTemplate and ContentTemplateSelector properties came from. We decided to make this implicit because we realized this is what people want most of the time. If, for some reason, you don’t want to use the Content of your ContentControl in its template, and want to use some other data instead, you can set the Content property of the ContentPresenter explicitly. For example, try replacing the ContentPresenter in the markup above with the following:
<ContentPresenter Content="{TemplateBinding Background}" Margin="10"/>
You will notice that the Button will display “#FF4682B4″ instead of “Hello”, even though we set its Content property to “Hello”.
In summary: ContentControl is a control that uses a template to display a single piece of content, and ContentPresenter is used to specify where the content should go in the ContentControl’s template.
Vivek
Any idea if MediaElement can play Mpeg or Avi files?
WMV looks good when the window is small, but for windows of bigger sizes its awful?
November 23, 2006 at 1:36 pm
Bea
Vivek,
For non-data binding WPF questions, please post in our forum.
Thanks,
Bea
November 24, 2006 at 1:08 pm
Kent boogaart
> is this a topic of interest?
You’ve got my vote.
November 24, 2006 at 6:46 am
Bea
Hi Kent,
Thanks for the feedback. I will write about that then.
Bea
November 25, 2006 at 1:09 pm
Al
Bea,
I think a lot of your examples are ok, but they really aren’t how the real world works, at least for me anyway.
For example, although my data comes to me in an xml format, it gets parsed and placed into an object. My binding needs to take place in code because each call for data can have a different number of columns, which will be unknown until I receive the data. I have a requirement for textboxes in each column header to act as input for a filter. Each row needs a checkbox that not only is bound to the ListViewItem’s IsSelected property but also bound to the data source. And on top of all of this is a very complex architecture that leaves everything loosely coupled.
So I guess what I am asking for is better examples. Show us not only how to bind with xaml, but in code as well. Show us observable collections with dynamic properties. Show us how to bind a checkbox to a ListViewItem’s IsSelected property _and_ to a property in the data source (my current problem that needs resolution).
Thanks,
Al
November 25, 2006 at 4:07 pm
Bea
Al,
Thanks for your feedback. I agree that real world apps are much more complex than the simple samples you find in my blog. But at the same time, all these samples are based on questions I received from customers that, like you, are writing big real world apps. I will be happy to write a sample that addresses the particular difficulties you are encountering while writing your app.
Replying to the scenarios you mentioned:
- I can certainly write my bindings in code in my next sample.
- Can you explain what you mean by dynamic properties in ObservableCollections? Are you using WPF’s property system?
- Anytime you want to bind to more than one source at a time, you should use MultiBinding. You can find a MultiBinding sample here. Let me know if this solves your problem.
Thanks,
Bea
November 26, 2006 at 9:10 am
Al
Hi Bea,
I’m sorry it’s taken so long to get back to you. In a static situation, the observable collection would have a set of properties that you would then map to each column in a list view, something like Name, Age, and Height for example. And that’s great for a static view. The data I work with isn’t static. I have one list view and when the data is returned it may have one column of data or ten, depending on the call being made. My list view needs to be able to handle the additional (or lack) of columns without resorting to hard-code properties (i.e., Name, Age, etc). I mean, I could have set of properties named Column1, Column2, etc, but that’s pretty kludgy. The solution to this problem was (and I’m not sure I completely understand everything) to create some classes to generate some custom properties for a collection utilizing the TypeDescriptionProvider, CustomTypeDescriptor and PropertyDescriptor classes. This creates a dynamic, custom set of properties for the collection so I can map my collection to the each column in the list view. As far as the MultiBinding example goes, try this. Use the example in the SDK for having a checkbox on a ListViewItem (How to: Create ListViewItems with a CheckBox). Bind the list view to an observable collection and additionally bind the checkbox checked state to a boolean in the observable collection. Show us the example with xaml and code. There is a definite lack of coding examples for Binding/MultiBinding in code and a few good examples would go a long way to help and for understanding.
Thanks,
Al
December 11, 2006 at 12:26 am
Bea
Hi Al,
Ah, yes, I understand your scenario with the dynamic properties and yes, CustomTypeDescriptor is the best solution. I added this topic to my list, so I will talk about it in a future post (not in the next one, since I have other topic requests before this one.)
I have one question about your ListView scenario. Are the CheckBoxes in the ListViewItems bound to one single property in the ObservableCollection, meaning they’re all checked or all unchecked? Or are they bound to a property on the items added to the ObservableCollection, which means some of them could be checked and others unchecked? From your description, it seems like you’re asking for the first, but I would expect the second one to be a more useful scenario.
Thanks,
Bea
December 12, 2006 at 11:05 am
Al
Bea,
It is the latter. The checkboxes are bound to a property on the items added to the ObservableCollection, so some checkboxes are unchecked and some are checked.
Al
December 13, 2006 at 4:59 pm
Peter Kellner
Is there someway with blend to work with templates? I end up cutting and pasting a lot and it gets kind of confusing.
August 30, 2007 at 7:11 am
Bea
Hi Peter,
Unfortunately I am not an expert in Blend. There is a forum where you can ask Blend questions - there are typically people from the Blend team watching the questions and replying.
I hope you can find answers to your questions there.
Thanks,
Bea
September 17, 2007 at 9:47 pm
Saxon
I found no sample code attached below ” try replacing the ContentPresenter in the markup above with the following:”
Are there any code missing? I’m using IE8
September 9, 2009 at 8:04 pm
Bea
Hi Saxon,
Thanks for letting me know. I’ve updated the blog post to include the missing code.
Bea
October 11, 2009 at 7:32 pm