Table of contents
- Part 1 (XAML): Learn about XAML and how it is used in WPF applications.
- Part 2 (Layout): Learn about layout panels and how they are used to construct user interfaces.
- Part 3 (Data binding): Learn how WPF data binding works and how it can be used.
- Part 4 (Data templates and triggers): Learn how data templates and triggers work and how they can be used.
- Part 5 (Styles): Learn about how UIs can be styled in WPF.
Introduction
This is the third article in an introductory series about the Windows Presentation Foundation. In the previous article we examined layout panels and how they are used to create WPF user interfaces. In this article we will explore the world of data binding, and how it is put to use in the WPF Horse Race demo application (which is available for download at the top of the first article in this series).
For a comprehensive review of WPF data binding be sure to refer to the links listed in the External links section at the bottom of the page. This article covers the bare essentials of WPF data binding, and demonstrates various ways in which the WPF Horse Race application uses data binding.
Background
Data binding in the user interface layer is nothing new. It has been around for quite some time, in various UI platforms, both for desktop and Web applications. The basic idea is that you "bind" the visual elements (controls) in a user interface to the data objects they are meant to display. The binding infrastructure then manages the data interactions from then on, so that modifications to the UI controls are reflected in the data objects, and vice versa. The major benefit of using data binding is that it reduces the amount of code the application developer needs to write.
The architects of some earlier UI platforms have done a good job integrating data binding with the rest of their framework. WPF's architects have done an amazing job integrating data binding with all aspects of their framework. Data binding in WPF is ubiquitous and seamless. It is so powerful and flexible that it literally forces you to change the way you think about designing and developing user interfaces.
With one simple API you can bind to domain/business objects, XML data, visual elements, ADO.NET data containers, collections, and basically anything else you can think of. You can use value converters to execute arbitrary data manipulation operations when bound values are passed back and forth. You can perform data validation by creating custom validation rules and applying them to a binding. The list goes on. Data binding in WPF is really a huge step forward.
Dependency properties
Before diving into the guts and glory of WPF data binding, it is necessary to take a detour and briefly discuss another fundamental feature of WPF which makes it all possible. In WPF a property can only be bound if it is a dependency property.
Dependency properties are like normal .NET properties on steroids. There is a whole dependency property infrastructure in place, which provides an array of features for application developers to make their lives easier. For our purposes in this article it is important to know the following things about dependency properties:
- They can determine their value by retrieving it from a
Binding object (i.e. they can be bound).
- They can participate in property value inheritance, meaning that if a dependency property on an element does not have a value it will use the value of that property on an ancestor element (in the logical tree). This is somewhat analogous to ambient properties in the Windows Forms world.
- They can be set in XAML, just like a normal property.
The reasons why those aspects of dependency properties are important will become clear later on, as we examine how data binding uses them. For more information about dependency properties, refer to the Dependency properties sub-section in the External links section at the bottom of this page.
DataContext
User interface elements in WPF have a DataContext dependency property. That property has the aforementioned "value inheritance" feature enabled, so if you set the DataContext on an element to a Foo object, the DataContext property on all of its logical descendant elements will reference that Foo object too. This means that all data bindings contained within that root element's element tree will automatically bind against the Foo object, unless explicitly told to bind against something else. This feature is extremely useful, as we will soon see.
The Binding class
Data binding in WPF revolves around the Binding class. Binding is the sun of the data binding solar system, so to speak.
That class has a fairly simple and intuitive API, but it is very powerful. The WPF Horse Race demo application does not nearly use all of the features of the Binding class, but it does make use of some common ones. Let's take a look at the Binding members we will see in action later on in this article.
- Source - references a
Binding's data source. By default this object references the element's DataContext value, which might be inherited from an ancestor element's DataContext, as discussed in the previous section. If you set this property to a non-null value, then the data binding operation will treat that value as the place where data is pushed to and pulled from.
- Path - is used to indicate from which property on the source object to get and set the bound data value. It is a property of type PropertyPath, which allows it to support a complex range of path expressions.
- ElementName - can be used as an alternative to the
Source property described earlier. It allows you to specify the name of an element to use as a data source. This can be useful when binding a property on one element to a property on another element, particularly when the binding is declared in XAML.
- Converter - of type IValueConverter. You can set this property to an instance of a class which implements that interface to intercept any movement of data from the binding source to the binding target, or vice versa. Value converters are very convenient and are used quite often.
How the WPF Horse Race uses data binding
Now that we have a general idea of how data binding is structured, it's about time to see how the WPF Horse Race demo application uses it. We won't examine each place that data binding is used in the application; some of them are better saved for a later article in this series. All of the data binding logic in the application is expressed in XAML, but keep in mind that it is entirely possible to do all of this in the code-behind as well.
Displaying a racehorse's name
Open the RaceHorseDataTemplate.xaml file, which contains the DataTemplate for the RaceHorse class (if you don't know what a DataTemplate is yet, don't worry, the next article in this series covers that topic). In that file there is a TextBlock named 'horseName' which is bound to the Name property of a RaceHorse object. Here's an abridged version of the XAML I'm referring to:
<TextBlock x:Name="horseName" Text="{Binding Name}" />
When a RaceHorse named 'Sweet Fate' is displayed in the UI, that TextBlock displays its name as seen below:
Notice that the binding statement in the XAML snippet above does not explicitly mention that it is setting the Binding's Path property. Markup extensions, such as Binding, can have one property which acts as the "default" property when being set in XAML. Binding's default property is Path. If you are not in favor of using implicit notation like that, the XAML seen below is equivalent to the previous snippet:
<TextBlock x:Name="horseName" Text="{Binding Path=Name}" />
Rotating the race track
In the main Window's XAML file (Window1.xaml) there is a Slider control which affects the rotation angle of the "race track" ItemsControl. The ItemsControl has its LayoutTransform property set to a RotateTransform resource, so the Slider must bind to that RotateTransform in order to affect the rotation of the ItemsControl. The result of this binding is that when the user moves the thumb in the Slider, the "race track" rotates, like this:

The following XAML is a skeletal outline of the Window, showing only the markup relevant to this particular binding:
<Window>
<Grid>
<Grid.RowDefinitions>
-->
<RowDefinition Height="*" />
-->
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.Resources>
<RotateTransform x:Key="trans" Angle="0" />
</Grid.Resources>
-->
<ItemsControl LayoutTransform="{StaticResource trans}" />
-->
<Border Grid.Row="1">
<Slider Value="{Binding Source={StaticResource trans}, Path=Angle}" />
</Border>
</Grid>
</Window>
Displaying the angle of rotation
Directly beneath the Slider in the main Window's XAML is a TextBlock whose Text property is bound to the Slider's Value property. The purpose of this TextBlock is to show the angle of rotation applied to the race track. Since this should display a user-friendly number, and the Slider's Value property is a double, a value converter is used to remove all of the decimal places (basically it casts the double to an int). Here's how that works:
<StackPanel>
<StackPanel.Resources>
<local:DoubleToIntegerConverter x:Key="conv" />
</StackPanel.Resources>
...
<Slider x:Name="rotationSlider" />
<TextBlock Text="{Binding
ElementName=rotationSlider,
Path=Value,
Converter={StaticResource conv}}"
/>
...
</StackPanel>
That binding uses the ElementName property to refer to the Slider element. It also uses a custom value converter to convert the Value property of the Slider to an integer. Below is the code for the value converter:
public class DoubleToIntegerConverter : IValueConverter
{
public object Convert(
object value, Type targetType,
object parameter, CultureInfo culture )
{
return (int)(double)value;
}
public object ConvertBack(
object value, Type targetType,
object parameter, CultureInfo culture )
{
throw new NotSupportedException( "Cannot convert back" );
}
}
Calculating the width of a racehorse's progress indicator
As a racehorse "runs the race" it is followed by a green progress indicator. That indicator's width represents what percent of the race the horse has completed as seen below:
Determining the width of the progress indicator requires two pieces of information: the percent of the race completed by the racehorse, and the total distance which the racehorse must travel to reach the finish line. Based on what we have seen of data binding in WPF so far, this seems like a problem. How can you bind the width of an element to a value whose calculation requires two numbers? That's where the MultiBinding and IMultiValueConverter types come into play.
Here's an approximation of how that works:
<Border x:Name="racePit">
<Grid>
<StackPanel>
<StackPanel.Resources>
<local:RaceHorseProgressIndicatorWidthConverter x:Key="WidthConv" />
</StackPanel.Resources>
-->
<Rectangle x:Name="progressIndicator"
Fill="{StaticResource RaceInProgressBrush}"
>
-->
<Rectangle.Width>
<MultiBinding Converter="{StaticResource WidthConv}">
<Binding Path="PercentComplete" />
<Binding ElementName="racePit" Path="ActualWidth" />
</MultiBinding>
</Rectangle.Width>
</Rectangle>
</StackPanel>
</Grid>
</Border>
The multi-value converter used to calculate the progress indicator's width is seen below:
public class RaceHorseProgressIndicatorWidthConverter : IMultiValueConverter
{
public object Convert(
object[] values, Type targetType,
object parameter, CultureInfo culture )
{
int percentComplete = (int)values[0];
double availableWidth = (double)values[1];
return availableWidth * (percentComplete / 100.0);
}
public object[] ConvertBack(
object value, Type[] targetTypes,
object parameter, CultureInfo culture )
{
throw new NotSupportedException( "Cannot convert back" );
}
}
External links
Dependency properties
Data binding
History
- April 3, 2007 � Created the article.
| You must Sign In to use this message board. |
|
|
 |
|
 |
So this article tells the reader a lot of theory but it's too confusing...... not a good way to learn. Take for instance,
public class DoubleToIntegerConverter : IValueConverter { public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) { return (int)(double)value; }
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) { throw new NotSupportedException( "Cannot convert back" ); } }
Yeah right ok..... where the heck do I put this? In the Window code behind? In the App code behind? In the App XAML file? In the Window XAML file? No clue. The article doesn't explain at all. So I want to try this by myself to learn and I don't know where to put this class. THANKS A LOT!!! (NOT)
|
| Sign In·View Thread·PermaLink | 1.15/5 |
|
|
|
 |
|
 |
Perhaps if you spent less time writing thoughtless rants, and more time learning the platform, it wouldn't be so difficult for you.
|
| Sign In·View Thread·PermaLink | 5.00/5 |
|
|
|
 |
|
 |
Learn what? WPF, C# or programming in general? Seriously, if you need that much hand holding on something like this example, you're starting at the wrong place. Learn other concepts before attempting to learn WPF.
BTW, you can figure this one out for yourself by looking at the supplied source code. Just go back to the first article in this series and download the source bundle.
William E. Kempf
|
| Sign In·View Thread·PermaLink | 5.00/5 |
|
|
|
 |
|
 |
William E. Kempf wrote: Seriously, if you need that much hand holding on something like this example, you're starting at the wrong place. Learn other concepts before attempting to learn WPF.
Well said, sir!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Kim I have to say I have learnt loads from this series of Joshs, WPF is hard your need to put the time in oh and perhaps read the downloaded code, that helps.
Sacha Barber- Microsoft Visual C# MVP 2008/2009
- Codeproject MVP 2008/2009
Your best friend is you. I'm my best friend too. We share the same views, and hardly ever argue My Blog : sachabarber.net
|
| Sign In·View Thread·PermaLink | 5.00/5 |
|
|
|
 |
|
 |
Word, Kim! I mean, look at that convert thingy you posted. Really complicated. All that codez. Not even picture. Why does this Josh think I have a TV? Because reading is totally boring. And computer is like TV. Not like a book!
Keep it up man, you're the bomb!
NetDrives - Open Source Network Share Management Awesomeness
|
| Sign In·View Thread·PermaLink | 5.00/5 |
|
|
|
 |
|
|
 |
|
 |
why you laughing at me? you think that's funny? you better send me teh codez or i'll give you bad vote! like 111111111111. that's all 1, not the big number with a lot of 1 in it!
NetDrives - Open Source Network Share Management Awesomeness
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
 |
Too complicated and confusing (badly written).... too much theory... boring........ lack of more pratical examples and step by step guidance..
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
 |
Perhaps if you weren't such a talentless no-hoper, you'd realise that WPF requires learning a lot of theory. While I appreciate that you can't find your arse from your elbow, I must point out that Josh isn't your personal frigging tutor - there comes a point where you have to get off your lazy arse and actually attempt to learn something for yourself.
Here's a news flash for you. Josh isn't being paid to do your thinking for you; he's not writing a book for you. He's given his time freely to help thousands of people learn WPF through his excellent articles. His writing style is easy to follow for those of us who have greater than a double digit IQ, and his knowledge has earned him the admiration of people the world over. If he were to attempt to cover all that he knows in a step by step manner, it would be a full sized book and you wouldn't be able to cope with reading it on the screen.
Here's a challenge for you - if you think Josh's articles are boring and poorly written, why don't you take up the mantle and write the definitive WPF articles? If you're so capable, it shouldn't be much trouble for you. Perhaps, when you've given as much to the WPF world as Josh has, I'll have more time for your putrid whining.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes. My blog | My articles | MoXAML PowerToys | Onyx
|
| Sign In·View Thread·PermaLink | 5.00/5 |
|
|
|
 |
|
|
 |
|
 |
Too complicated and confusing (badly written).... too much theory... lack of more pratical examples and step by step guidance..
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
 |
Hi,
The last days I've tried to work with the mvvm-pattern and it is al comming clear to me. But yesterday I've encountered a problem when I want to make use of a scrollviewer in a tabitem.
So I have a tabcontrol that is bound to a list of projects (just like you would have a tab for each document in MS excel). So for every project I create an tabitem that has content (through an item template). Then I put an Scrollviewer on that tabitem to get all my information in that tab.
Now the problem is that there is no way (at least I didn't found one), to bind a scrollviewers current scrollbar position (X_Y) to a viewmodel. So if I scroll in the first tab, then the second tabs also scrolls ... .
You can simulate this problem in your project you have explained here.[^]. In customerview put a scrollviewer around your Grid and give the grid a height (e.g. 500) ... open multiple new customerpanels, scroll down on the first tab ... and you will notive they all have scrolled.
Any ideas to solve this ?
Greetings, Kevin
I've posted this also on the MSDN forums: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/6cc5a7c2-6300-4ac8-837b-5f995ae70670[^]
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I doubt ScrollViewer can be bound to in this way. ScrollViewer exposes methods to scroll to a given offset (ScrollToHorizontalOffset and ScrollToVerticalOffset), instead of allowing you to set the offset via a property. You will have to write some code to handle this, either in the code-behind of the View containing the TabControl, or as an attached behavior[^].
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
 | Thanks  laserbeak43 | 10:03 23 Apr '09 |
|
|
 |
|
 |
I need to do the following in C# instead of XAML. How do I do it?
<Image x:Name="myImage" Grid.Column="0" Stretch="None" Width="16" Height="22" > <Image.Source> <MultiBinding x:Name="imageLeftCapMultiBinding" Converter="{StaticResource myconverter}" > <Binding ElementName="btnOne" Path="IsPressed" /> <Binding ElementName="btnOne" Path="IsMouseOver" /> <Binding ElementName="stackpanelButtonContainer" Path="IsMouseOver" /> </MultiBinding> </Image.Source> </Image>
I try this but of course it doesn't work this way: myImage.Source = new MultiBinding();
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Josh,
First of all thanks again for the last message here, where you helped me out. Now its the second time, I am having problem. Show me some light again!!!
Basically, I have a TreeView and a ListView. When users changes the selection of TreeNode then, I updated the Listview with some relevant data to that selected TreeNode. But I am using a converter here to populate the data for the ListView. The binding xaml of the ListView is as follows
<listbox x:name="datagrid" datacontext="{Binding Path=SelectedValue, Converter={StaticResource DocumentConverter}, ElementName=myTree}" ></listbox>
Now, I have a button at some where into the same window, and I want when user will click onto that button, I would like to refresh the ListBox data. Basically the logic of the converter does something different when a button has been clicked. So, if somehow i was able to re-execute the converter code that is my target. In short, I need to invalidate the DataContext of the ListBox when the button gets clicked.
Did you get my problem?
If you could light me on this issue- that would be a great great help for me. please suggest!!
Thanks in advance!
Moim Hossain Senior Software Engineer KAZ Software
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
|
 |
|
 |
Josh, first of all thanks for the great contributions on WPF here. hey I am running a trouble here..lets see if you can light me here.. I have an object data source defined..that is using a plain .net class to fetch some data. for instance, the class is as follows
class Manager { public static []Department GetDepartments() { ... } public static []Employee GetEmployees(string departmentName) { ... } }
Now, I have a combo box that is bound to the GetDepartment method by using an object data source. What i need now is, another combo box will reflect the employee names based onto the current selected department. I tried another object data source for this, but as the object data source is not a dependencyObject It can't take the selected department name as a method parameter.
Would be nice to hear a expert solution from you? Best regards
Moim Hossain Technical Lead (.NET) Orion Informatics.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Set each ComboBox's IsSynchronizedWithCurrentItem property to true. This will enable a new selection in the Employee box to "notify" the Department box that it should update it's value. Of course, this all assumes that you're databinding these two boxes to the same data source.
:josh: My WPF Blog[ ^] All of life is just a big rambling blog post.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I have an object data source with static methods to get the actual data. do u think this fits to my scenario..?
Moim Hossain Technical Lead (.NET) Orion Informatics.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Moim Hossain wrote: I have an object data source with static methods to get the actual data. do u think this fits to my scenario..?
Where the data comes from is irrelevant to the binding system. Data binding is all about reflection and interfaces.
:josh: My WPF Blog[ ^] All of life is just a big rambling blog post.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
 | local:  Peregrinati | 7:41 22 Nov '07 |
|
 |
Hi, I'm brand new the WPF (though pretty good with C# / WinForms), and honestly, I'm finding it highly confusing.
Anyways, I'm trying little bits of your code out in Visual C# 2008, and I just tried to do the type converter. I created the DoubleToIntegerConverter class in the same namespace as my Window1 which contains a StackPanel. I'm then trying to add resources to the StackPanel, as per your code:
<StackPanel.Resources> <local:DoubleToIntegerConverter x:Key="conv" /> </StackPanel.Resources>
However, there seems to be a problem with the "local" - it just won't accept it. Any idea why?
Also, in my efforts to understand things I was mucking about and tried to set the width of the entire "slider" control (border?) equal to exactly half Grid's width. No reason - it's just something that I'd find trivial in WinForms, but can't figure out in WPF, so it's bothering me. Is it possible to do something like "Border.Width = Grid.Width /2", or am I thinking completely wrong?
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
|