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=http://schemas.microsoft.com/winfx/2006/xaml/presentation


  xmlns:x=http://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 (15)

  1. BobStrogg says:

    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 :)

  2. wcsdkteam says:

    Wow, that’s a really cool demo, Chris! Somehow I really enjoy seeing the car rolling off the screen. :) Thanks for sharing! – Tina

  3. Hi there, I’m trying hard to find out the event that will be raised when data binding. Example, I’m binding to a DataTable in a Dataset, and displaying the result using ListView. All I wanted to do is to construct a custom ContextMenu for each item in the ListView during data binding. The context menu content will vary from item to item (atleast the enabled property will change). At the moment I got the ContextMenu element for the ListView in XAML using ListView.ContextMenu element. Its showing the ContextMenu on each line item as expected, but since its referencing to a single context menu, any property change in MenuItem is reflected on each row.

    Any thoughts?

    Saravana

  4. wcsdkteam says:

    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,

    Tina

  5. Ben.Henderson says:

    Tina, thanks so much for this FAQ. You really helped me over the hump in areas areas.

    – Ben

  6. johnds says:

    Hi Tina,

    I am struggling with WPF binding, trying to do the simplist thing, but it doesnt seem to work.

    I have a simple WPF application, with a Window XAML and code behind, nothing unusual. In my code behind file, I have a public instance property of the Window class. I simply want to bind that property to the text of a textbox, bound TwoWay.

    It’s amazing, i just cant seem to get it to work!

    How on earth do you bind custom properties of the containing class (Be-it an Window, UserControl, whatever), to UI elements which the class contains??????????????

  7. Carole Snyder says:

    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.

    Carole

  8. thrivingtoday says:

    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.

    John

  9. Carole Snyder says:

    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,

    Carole

  10. Jackao says:

    Very nice post! You're very kind! Thx!

  11. Robert C Taubert says:

    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

  12. Ashish sajwan says:

    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 me

  13. Carole Snyder says:

    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.

  14. anonymous says:

    Its x:Name

    <local:Person x:Key="myDataSource" Name="Joe"/>