WPF FAQ - DataBinding

Find answers for the most frequently asked questions
Expand All Collapse All

The most common binding scenarios involve the data getting updated from the source to the target. But, in some cases, the source has to be updated when changes are made by the users in the target. Such cases can be defined using the ‘BindingModes’ of the Binding markup extension class. ‘BindingModes’ is an enumeration property and it takes the following values.

1. OneWay – The target is updated whenever the source is updated.

2. TwoWay – A change to either the target or source updates the other.

3. OneWayToSource – It is an opposite of OneWay. The source is updated whenever the target value changes.

4. OneTime – It is similar to OneWay except that the changes to the source are also not reflected in the target. The target contains the value of the source when Binding was initiated.

Permalink

Every FrameworkElement can be associated with a DataContext which will be used as the default data source during binding, if no other data source is specified in the binding code. Also, the children of this FrameworkElement auotmatically inherit this setting. This helps having to repeatedly specify this data source as the source of a binding, thereby letting you simplify the binding code.

The following code snippet is an example of implicit datasource using DataContext.

[XAML]

<StackPanel x:Name='Class' DataContext='{StaticResource student}'>
<Label x:Name='studcount' Content='{Binding Path=Count}'/>
<ListBox x:Name='Studname' DisplayMemberPath='Name' ItemsSource='{Binding}'/>
</StackPanel>

Permalink

Sometimes you might have to specify a HierarchicalDataTemplate for a templated type. If so, you can only do this in code-behind. (If you have to do this in XAML try wrapping that template type within a non-templated dummy type.)

For example, if you have to do something like this:


            <HierarchicalDataTemplate ItemsSource='{Binding}'  
                                      DataType='{x:Type local:MyTemplatedList<int>}'>   
                <TextBlock Text='{Binding Name}'></TextBlock>  
            </HierarchicalDataTemplate>  

The above wouldn’t compile because the XAML compiler doesn’t support this.

So, you will have to do this in code-behind instead:


using MyListType = MyTemplatedList;

// Then in Window’s constructor for example:
HierarchicalDataTemplate hdt = new HierarchicalDataTemplate(typeof(MyListType));   
hdt.ItemsSource = new Binding();   
FrameworkElementFactory tb = new FrameworkElementFactory(typeof(TextBlock));   
tb.SetBinding(TextBlock.TextProperty, new Binding('Name'));   
hdt.VisualTree = tb;   
this.Resources[new DataTemplateKey(typeof(CountryList))] = hdt;  

Note that the above code also illustrates how to add a HierarchicalDataTemplate resource to the Resources list without specifying a key.

Permalink

To specify custom sorting using a custom implementation of an IComparer, you will have to use a CollectionViewSource, get it’s default view and set it’s CustomSort property as follows:

Sample ListBox bound to a CollectionViewSource:


<Window x:Class='WindowsApplication1.Window1'
    xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
    xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
    xmlns:scm='clr-namespace:System.ComponentModel;assembly=windowsbase'
>
  <Window.Resources>
    <XmlDataProvider x:Key='list' >
      <x:XData>
        <Items xmlns=''>
          <Item>
            <Name>David</Name>
            <Age>20</Age>
          </Item>
          <Item>
            <Name>Marcus</Name>
            <Age>25</Age>
          </Item>
          <Item>
            <Name>George</Name>
            <Age>25</Age>
          </Item>
          <Item>
            <Name><![CDATA[Peter&#M]]></Name>
            <Age>25</Age>
          </Item>
        </Items>
      </x:XData>
    </XmlDataProvider>
    <CollectionViewSource
        Source='{Binding Source={StaticResource list}, XPath=Items/Item/Name}'
        x:Key='data'/>
  </Window.Resources>
  <ListBox
      Name='lb1'
      DisplayMemberPath='Name'
      ItemsSource='{Binding Source={StaticResource data}}'/>
</Window>

Then in code-behind specify the custom comparer as follows:


public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        this.lb1.Loaded += delegate
        {
            CollectionViewSource cvs = this.TryFindResource('data') as CollectionViewSource;
            if (cvs != null)
            {
                ListCollectionView view = cvs.View as ListCollectionView;
                if (view != null)
                {
                    view.CustomSort = new XmlComparer();
                }
            }
        };
    }

    public class XmlComparer : IComparer
    {
        public Int32 Compare(Object x, Object y)
        {
            XmlElement a = x as XmlElement;
            XmlElement b = y as XmlElement;
            if (a != null && b != null)
            {
                return String.Compare(a.InnerText, b.InnerText);
            }

            return -1;
        }
    }
}
Permalink

As with support for parameterized constructor, this is most useful for existing classes that are not databinding-friendly and can’t be changed. For your own types, you might as well expose potential datasources as properties. But note that the photos collection exposed a method call ‘GetFolderName’, that returned a string representing the folder containing all the current items. You could expose this method as a datasource as follows.

[XAML}

<ObjctDataProvider x:Key='dataProvider' ObjectType='{x:Type Local:Photos}' MethodName='GetFolderName'/>

If the parameters need to be passed to the method, you can use ObjectDataProvider’s ‘MethodParameters’ property ( which works just like it’s ConstructorParameter property).

To Bind this method, simply bind it to the entire ObjectDataProvider.

[XAML]

<TextBlock Text='{Binding source={StaticResource dataProvider}}'/>

Specifying the path in this case would apply to the instance returned by the method.

Permalink

When TwoWay BindingMode is used, the XMLDataProvider writes the data to the ‘in – memory’ XML file and it does not write to the file in your hard disk. You have to perform your own serialization to write the data updated to the XML file in the hard disk.

Permalink

The ‘RelativeSource’ property of the Binding class is used to bind the data from an element by it’s relationship to the source element. RelativeSource is also a markup extension of type RelativeSource.

The following are some of the ways that RelativeSource can be used.

1. When the source element is equal to the target element,

[C#]

{Binding RelativeSource={RelativeSource Self}}

2. When the source element is equal to the target element’s TemplatedParent,

[C#]

{Binding RelativeSource={RelativeSource TemplatedParent}}

3. When the source element is equal to the closest parent of a given type,

[C#]

{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type StackPanel}}, Path=Orientation}

4. When the source element is equal to the nth closest parent of a given type,

[C#]

{Binding RelativeSource={RelativeSource FindAncestor,AncestorLevel=1, AncestorType={x:Type Window}}, Path=Title}

5. When the source element is equal to the previous data item in a data – bound collection.

[C#]

{Binding RelativeSource={RelativeSource PreviousData}}
Permalink

Setting this property provides an alternative to use the DataErrorValidationRule element, explicitly. The DataErrorValidationRule is a built-in validation rule that checks for errors that are raised by the ‘IDataErrorInfo’ implementation of the source object. If an error is raised, the binding engine creates a ValidationError with the error and adds it to the ‘Validation.Errors’ collection of the bound element. The lack of an error clears this validation feedback, unless another rule raises a validation issue.

This example shows how to implement validation logic on a custom object and then bind to it.

You can provide validation logic on the business layer if your source object implements IDataErrorInfo, as in the following example. In the following example, the ‘text’ property of the textbox binds to the ‘Age’ property of the Person object which has been made available for binding through a resource declaration that is given in the x:Keydata. The ‘DataErrorValidationRule’ checks for the validation errors raised by the IDataErrorInfo implementation.

[XAML]

<TextBox Style='{StaticResource textBoxInError}'>
    <TextBox.Text>
        <!--By setting ValidatesOnExceptions to True, it checks for exceptions
        that are thrown during the update of the source property.
        An alternative syntax is to add <ExceptionValidationRule/> within
        the <Binding.ValidationRules> section.-->
        <Binding Path='Age' Source='{StaticResource data}'
                 ValidatesOnExceptions='True'
                 UpdateSourceTrigger='PropertyChanged'>
            <Binding.ValidationRules>
                <!--DataErrorValidationRule checks for validation 
                    errors raised by the IDataErrorInfo object.-->
                <!--Alternatively, you can set ValidationOnDataErrors='True' on the Binding.-->
                <DataErrorValidationRule/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>
Permalink

A parameter can be passed to a function using the ‘MethodParameters’ of the ‘ObjectDataProvider’ class.

The following XAML code snippet demonstrates how to pass parameters to a function using an ObjectDataProvider.

[XAML]

<ObjectDataProvider ObjectInstance='{StaticResource odp1}' MethodName='WeightOnPlanet' x:Key='odp2?>
<ObjectDataProvider.MethodParameters>
<system:Double>95</system:Double>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

Permalink

The source can be updated using the ‘UpdateSourceTrigger’ property of the TextBox. By default, the ‘UpdateSourceTrigger’ property is set to ’LostFocus’, i.e. the source is updated when the data-bound TextBox loses the focus. By setting the ‘UpdateSourceTrigger’ property to ’PropertyChanged’, the source will be updated as you type in a TextBox.

In the following code snippet a TextBox’s ‘Text’ property is bound with the Button’s ‘Width’ property. On changing the Text in the TextBox, the Width of the Button is updated.

[XAML]

<Button Name='hellobtn' Content='Hello' Width='150' Height='30'/>
<TextBox Text='{Binding ElementName=hellobtn, Path=Width, Height='20' UpdateSourceTrigger=PropertyChanged}'/>
Permalink

ItemControl’s items and ItemsSource can’t be modified simultaneously. ItemControl’s ‘Items’ property is used to add items manually and ‘ItemsSource’ property is used to bind the ItemControl with the datasource. You must not mix these techniques, simply for the reason that ItemsSource can only be set when there are no items in the Item collection and Items can only be set when the ItemsSource is set to null. Otherwise you’ll get an ‘InvalidOperation’ Exception. Note that regardless of which method you use to set items in an ItemControl, you can always retrieve items using the ItemsCollection.

Permalink

ObjectDataProvider provides the ability to pass the parameters to the constructors using the ‘ConstructorParameters’ property.

The following code snippet demonstrates how to pass parameters to a constructor.

[XAML]

<ObjectDataProvider ObjectType='{x:Type local:odpsource}' x:Key='obj1?>
<ObjectDataProvider.ConstructorParameters>
<system:Double>2000</system:Double>
</ObjectDataProvider.ConstructorParameters>
</ObjectDataProvider>

Permalink

ObjectDataProvider is a class that wraps your source object to provide some extra functionality.

The following are the distinguishing capabilities of ObjectDataProvider.

  • Passing parameters to the constructor.
  • Binding to a method (with or without parameters).
  • Replacing the source object.
  • Creating the source object asynchronously.
  • Permalink

    An XMLDataProvider can be used when your datasource is an XML file.

    The following are some of the uses of XMLDataProvider.

  • XML can be pre-filtered using the XPath query of the XMLDataProvider.
  • It automatically reads the XML using a background thread without blocking the UI.
  • Data can be shared among the several controls.
  • If your XML uses Namespaces, then it is the convenient place to assign the XMLNamespaceManager.
  • Permalink

    Share with

    Couldn't find the FAQs you're looking for?

    Please submit your question and answer.