WPF Basic Data Binding FAQ
Through talking to people and monitoring both internal and external forums, I have compiled a list of questions people often have when first learning about WPF data binding. If you have any questions, please leave a comment and let me know!
What is target and what is source?
In WPF, you typically use data binding to establish a connection between the properties of two objects. In this relationship, one object is referred to as the source and one object is referred to as the target. In the most typical scenario, your source object is the object that contains your data and your target object is a control that displays that data.
For instance, consider a Person class with a Name property. If you want to show the Name property value in the UI and have the UI automatically change when the Name property value changes at run-time, you can bind the TextBlock.Text property to the Name property of the Person object. In the following example, the Person class is declared in the BindingSample namespace. When you run this, your window shows “Joe”.
<Window
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BindingSample">
<Window.Resources>
<!-- Instantiates the Person class with the Name value "Joe"-->
<!-- Giving it an x:Key so it's available as a resource -->
<local:Person x:Key="myDataSource" Name="Joe"/>
</Window.Resources>
<!-- Binding the Text property to the Name property -->
<TextBlock Text="{Binding Source={StaticResource myDataSource}, Path=Name}"/>
</Window>
So, in this example:
- The TextBlock is the target object.
- The Text property is the target property.
- The Person object is the source object.
- The Name property is the source property.
You bind a target to a source.
What’s bindable?
A target property must be a dependency property. This means that your target object must be a DependencyObject. Fortunately, most UIElement properties are dependency properties and most dependency properties, except read-only ones, support data binding by default. To find out if a property is a dependency property, check to see if it has a corresponding field that ends with “Property”. For example, the Text property is a dependency property and has a corresponding field named “TextProperty”. Alternatively, if you are using the SDK documentation, see if the property page has a “Dependency Property Information” section. If it does, then it is a dependency property. For an example, check out the Background property page.
Your source can be any CLR object or XML data:
- You can bind to any CLR objects, including list objects. You can bind to the entire object or public properties, sub-properties, and indexers of the object. Fields are not supported. The binding engine uses CLR reflection to get the values of the properties. Alternatively, objects that implement ICustomTypeDescriptor or have a registered TypeDescriptionProvider also work with the binding engine.
- You can bind to ADO.NET objects such as DataTable.
- You can bind to an XmlNode, XmlDocument, or XmlElement, and run XPath queries on them.
When do I use Source and when do I use DataContext?
There are many ways to specify your binding source, that is, to specify where your data is coming from. The simplest way is to instantiate the source object as a resource in XAML and then the Source property of the Binding to that resource (as in the last example).
Using the Source property is simpler and more readable. However, if multiple properties bind to the same source, consider using the DataContext property. The DataContext property provides a convenient way to establish a data scope. Say you have many controls and you want all of them to bind to the same source.
<Window . . .>
<Window.Resources>
<local:Person x:Key="myDataSource" Name="Joe"/>
</Window.Resources>
<StackPanel>
<StackPanel.DataContext>
<Binding Source="{StaticResource myDataSource}"/>
</StackPanel.DataContext>
<TextBox Text="{Binding Path=Name}"/>
<TextBlock Text="{Binding Path=Name}"/>
<!-- ...
Other controls that are also
interested in myDataSource.
...
-->
</StackPanel>
</Window>
In this case, you set the DataContext property of your StackPanel to that source so that all elements in that StackPanel inherit that common source. The TextBox and TextBlock in this example both inherit the binding source from the StackPanel. When you run this, you see a TextBox with “Joe” and a TextBlock with “Joe”.
How do I make my data-bound TextBox update the source value as I type?
By default, TextBox.Text has an UpdateSourceTrigger value of LostFocus. This means if you have a data-bound TextBox, the default behavior is that the source does not get updated until the TextBox loses focus. If you want the source to update as you type into the TextBox, set the UpdateSourceTrigger property to PropertyChanged:
<TextBox Text="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}"/>
One thing that’s really easy to miss is that the UpdateSourceTrigger default value varies for different properties. For most properties, the UpdateSourceTrigger property defaults to PropertyChanged. However, for TextBox.Text, it is LostFocus.
This table provides a summary of the UpdateSourceTrigger value for TextBox.Text. Again, remember that this is only true for the TextBox.Text property.
UpdateSourceTrigger value |
When the Source Value Gets Updated |
Example Scenario for TextBox |
LostFocus (default for TextBox.Text) |
When the TextBox control loses focus |
A TextBox that is associated with validation logic |
PropertyChanged |
As you type into the TextBox |
TextBox controls in a chat room window |
Explicit |
When the application calls UpdateSource |
TextBox controls in an editable form (updates the source values only when the user clicks the submit button) |
What does OneWay or TwoWay binding mean?
These are binding Mode values. In the simplest terms, the OneWay mode is read-only (with respect to the source) and the TwoWay mode is read-write. For instance, in a stock ticker application, your controls are only “reading” and displaying the source values, so the controls only need to have OneWay bindings. The read-write scenario with TwoWay bindings is more applicable to a business application that allows users to both view and edit data.
Similar to UpdateSourceTrigger, the default value for the Mode property varies for each property. User-editable properties such as TextBox.Text, ComboBox.Text, MenuItem.IsChecked, etc, have TwoWay as their default Mode value. To figure out if the default is TwoWay, look at the Dependency Property Information section of the property. If it says BindsTwoWayByDefault is set to true, then the default Mode value of the property is TwoWay. To do it programmatically, get the property metadata of the property by calling GetMetadata and then check the boolean value of the BindsTwoWayByDefault property.
There’s also OneWayToSource and OneTime. If you’re interested, see the Mode page in the SDK.
My target binds to a property on my custom object but the binding does not refresh when the source value changes.
Your custom object needs to implement a mechanism to provide notifications when a property changes. The recommended way to do that is to implement INotifyPropertyChanged. Here’s an example:
using System.ComponentModel;
namespace BindingSample
{
public class Person : INotifyPropertyChanged
{
private string name;
// Declare the event
public event PropertyChangedEventHandler PropertyChanged;
public Person()
{
}
public Person(string value)
{
this.name = value;
}
public string Name
{
get { return name; }
set
{
name = value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged("Name");
}
}
// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
}
Also, remember that the properties you are binding to need to be public and you cannot bind to fields.
How do I create a binding in code?
One way is to call the SetBinding method on the target object:
Person myDataSource = new Person("Joe");
Binding myBinding = new Binding("Name");
myBinding.Source = myDataSource;
// myText is an instance of TextBlock
myText.SetBinding(TextBlock.TextProperty, myBinding);
Only FrameworkElements and FrameworkContentElements have a SetBinding method. Their SetBinding method is actually calling the BindingOperations.SetBinding method. Therefore, you can always use the BindingOperations.SetBinding method, especially when your target object is not a FrameworkElement or a FrameworkContentElement.
How do I bind to an existing object instance?
In some cases the source object that you bind to can only be created at run-time, such as a DataSet object that’s created in response to a database query. In those cases, you need to set the DataContext property of your target object to the instantiated object programmatically. Example:
// myListBox is a ListBox control
// myCustomBizObject is your custom business object
myListBox.DataContext = myCustomBizObject;
There are two special cases. First, if you are binding to a property of another element in the same scope, then you use the ElementName property to specify the source. For example, you can bind the TextBlock.Text property to the content of the SelectedItem of a ComboBox:
<ComboBox Name="myComboBox" SelectedIndex="0">
<ComboBoxItem>1</ComboBoxItem>
<ComboBoxItem>2</ComboBoxItem>
<ComboBoxItem>3</ComboBoxItem>
</ComboBox>
<TextBlock Text="{Binding ElementName=myComboBox, Path=SelectedItem.Content}"/>
Second, if you are binding between properties of the same control, then you use the RelativeSource property. Specially, you set RelativeSource to Self: RelativeSource={x:Static RelativeSource.Self}.
In the next data-binding post we’ll get into common questions that deal with binding to collections and other more advanced scenarios. In the meantime, there’s always the Data Binding Overview in the SDK docs and Beatriz’s excellent blog.
Happy binding,
Tina
About Us
We are the Windows Presentation Foundation SDK writers and editors.
Comments
Anonymous
October 24, 2006
I've made a WPF demo that uses the Newton Game Dynamics physics engine to roll some things down the screen, all using databinding. You might want to check it out: http://chriscavanagh.wordpress.com/2006/10/23/wpf-2d-physics :)Anonymous
October 26, 2006
Wow, that's a really cool demo, Chris! Somehow I really enjoy seeing the car rolling off the screen. :) Thanks for sharing! - TinaAnonymous
December 05, 2006
The comment has been removedAnonymous
December 05, 2006
Hi Saravana, I may be simplifying your problem but would something like the following work in your scenario? <ListView.ContextMenu> <ContextMenu> <MenuItem Header="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem.Content}"/> </ContextMenu> </ListView.ContextMenu> If not, perhaps you can send us a simplified version of your code so we can take a look. Thanks, TinaAnonymous
August 13, 2007
The comment has been removedAnonymous
June 14, 2009
The comment has been removedAnonymous
June 16, 2009
Hi John, I created a simple sample that binds a TextBox to a property called AString on a Window and binds a Label to the same property: <Window x:Class="ThemeResource.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:ThemeResource" (Change this value to match the namespace in your project} Title="Window1" Height="300" Width="300"> <StackPanel > <Label Content="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:Window1}}, Path=AString}"/> <TextBox Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:Window1}}, Path=AString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> </StackPanel> </Window> When you type into the textbox, AString changes, but the label content doesn't because the label doesn't know that the property changed. To notify Label that the property changes, I implemented INotifyPropertyChanged on my Window1 class: public partial class Window1 : Window, INotifyPropertyChanged { public Window1() { InitializeComponent(); AString = "this is a string"; } string s; public string AString { get { return s; } set { s = value; OnPropertyChanged("AString"); } } #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; // Create the OnPropertyChanged method to raise the event protected void OnPropertyChanged(string name) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(name)); } } #endregion } Hope that helps. CaroleAnonymous
June 20, 2009
Tina, Thanks for this article. I have an application that's essentially a master-detail application. My main window contains a TreeView. The details are viewed through several usercontrols. How do I bind the textboxes and listviews from the usercontrols to the SelectedItem of the Treeview? Thanks. JohnAnonymous
June 22, 2009
Hi John, You can bind the DataContext of your user controls to the selected item in the treeview like this: <src:UserControl1 Grid.Row="5" DataContext="{Binding ElementName=Master, Path=SelectedItem}"/> Then in the use control you can bind to properties of the selected object. For example, if your TreeView is bound to an object that has a property called Description, you can put the following in your user control to display Discription's value: <TextBlock Text="{Binding Path=Description}"/> Hope that helps, CaroleAnonymous
July 14, 2010
Very nice post! You're very kind! Thx!Anonymous
August 15, 2010
This has been driving me nuts for three days. I have read the pertinent parts of the book I have, "Pro WPF in VB2010", I have read the web pages on binding on MSDN and still can't make sense of why this won't work. There is not a single sample I can find on binding to a class such as this. I am working with the sample app from the Win7 SDK...Samples...Samples WPF...Photo App. It was written to show the photos from a folder and when a photo is selected, show EXIF data about the image. I am trying to convert it to use Windows Properties. I have a Class, which works, that will provide the values for the Windows Properties that I am interested in. After instantiation I can display one of the properties in a MsgBox so I am pretty sure the class is working. What I cannot do is bind it to a TextBox in the MainWindow.xaml form. According to what I think I understand about binding, it should work. For the sake of brevity, I have left out a lot of code. I hope I didn't leave out anything important.
MainWindow.xaml <Window x:Class="SDKSamples.ImageSample.MainWindow" xmlns="schemas.microsoft.com/.../presentation" xmlns:x="schemas.microsoft.com/.../xaml" Title="WPF Photo Viewer w/Properties" Loaded="OnLoaded" xmlns:er="clr-namespace:SDKSamples.ImageSample" xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"> <!-- xmlns:ppm="clr-namespace:SHPropertyMetadata;assembly=clsShPropertyMetadata"> --> <-- I have tired it with and without this line --> <Dock Panel> <GroupBox> <ScrollViewer> <StackPanel> <Grid> <!-- Title --> <Label Grid.Row="13" Grid.Column="0" Content="Title:" VerticalAlignment="Center" /> <TextBox Grid.Row="13" Grid.Column="1" Text="{Binding Path=ppm.Title}" VerticalAlignment="Center" /> </Grid> </StackPanel> </ScrollViewer> </GroupBox> </DockPanel> </Grid> </Window>
MainWindow.xaml.vb Namespace SDKSamples.ImageSample Partial Public NotInheritable Class MainWindow Inherits Window Public Photos As PhotoCollection Public Sub New() InitializeComponent() End Sub Public ppm As SHPropertyMetadata.ShellPropertyMetadata Private Sub OnPhotoSingleClick(ByVal sender As Object, ByVal e As RoutedEventArgs) Dim imgPath = Me.ImagesDir.Text Dim imgName = HttpUtility.UrlDecode(System.IO.Path.GetFileName(PhotosListBox.SelectedValue.ToString)) Dim imgFullPath As String = System.IO.Path.Combine(imgPath, imgName) ppm = New SHPropertyMetadata.ShellPropertyMetadata(imgFullPath) MsgBox(ppm.Title) <-- This works, it show the correct information for the image clicked --> End Sub End Namespace
Anonymous
April 24, 2011
hey guys i want to a solution of my problem can u help me. how can i show data in datagrid without using itemsource .When I used itemsource to show the data then a problem occur 'System.IndexOutOfRangeException' occurred in System.Data.dll ,can you guys help me to solve this problem. There are a template column i used in datagrid.pls help meAnonymous
April 26, 2011
Hi Ashish, Generally, the best place to get your question answered is the MSDN forums at social.msdn.microsoft.com/.../threads. I'm not sure why you are getting an exception, but if you want to data bind your DataGrid, then you do need to use ItemsSource. If you ask your question on the forum and give a few more details (such as what are you trying to bind to), someone there might be able to help you, Thanks.Anonymous
January 11, 2012
Its x:Name <local:Person x:Key="myDataSource" Name="Joe"/>Anonymous
October 01, 2012
Good one.