Data Binding
Data Binding
Data Context
When data binding is declared on XAML elements, they resolve data binding by looking at their
immediate DataContext property. The data context is typically the binding source object for the binding source value
path evaluation.
For example, if you bound the content of a TextBox to the Employee.Name property, you would
set up your binding like the following table:
Setting Value
Target TextBox
Target property Text
Source object Employee
However, if the UpdateSourceTrigger value is LostFocus, then that value only is updated with
the new value when the target property loses focus.
6.1 Create a binding
To restate some of the concepts discussed in the previous sections, you establish a binding
using the Binding object, and each binding usually has four components: a binding target, a
target property, a binding source, and a path to the source value to use. This section discusses
how to set up a binding.
Binding sources are tied to the active DataContext for the element. Elements automatically
inherit their DataContext if they've not explicitly defined one.
<DockPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:SDKSample">
<DockPanel.Resources>
<c:MyData x:Key="myDataSource"/>
</DockPanel.Resources>
<DockPanel.DataContext>
<Binding Source="{StaticResource myDataSource}"/>
</DockPanel.DataContext>
<Button Background="{Binding Path=ColorName}"
Width="150" Height="30">
I am bound to be RED!
</Button>
</DockPanel>
6.2 Specifying the binding source
1. Using the DataContext property on a parent element is useful when you're binding multiple properties to the
same source The Parent : The dock panel defines its DataContext, say, Binding Object. In this example the
button sits inside the dock panel. It therefore inhertis its parent’s dataContext.
2. Inside an element
However, sometimes it may be more appropriate to specify the binding source on individual binding
declarations. For the previous example, instead of using the DataContext property, you can specify the
binding source by setting the Binding.Source property directly on the binding declaration of the
button, as in the following example.
<DockPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:SDKSample">
<DockPanel.Resources>
<c:MyData x:Key="myDataSource"/>
</DockPanel.Resources>
<Button Background="{Binding Source={StaticResource myDataSource}, Path=ColorName}"
Width="150" Height="30">
I am bound to be RED!
</Button>
</DockPanel>
3. you can also use the Binding.ElementName property . The ElementName property is useful when you're
binding to other elements in your app, such as when you're using a slider to adjust the width of a button.
4. The RelativeSource property is useful when the binding is specified in a ControlTemplate or a Style. For
more information, see Binding sources overview.
6.3 Specifying the path to the value
If you want to bind to an entire object, the value to use would be the same as the binding source object. In
those cases, it's applicable to not specify a Path. Consider the following example.
<ListBox ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="true"/>
The above example uses the empty binding syntax: {Binding}. In this case, the ListBox inherits the DataContext from a
parent DockPanel element (not shown in this example). When the path isn't specified, the default is to bind to the
entire object. In other words, in this example, the path has been left out because we are binding
the ItemsSource property to the entire object. (See the Binding to collections section for an in-depth discussion.)
Consider the following example, where myDataObject is an instance of the MyData class, myBinding is
the source Binding object, and MyData is a defined class that contains a string property
named ColorName. This example binds the text content of myText, an instance of TextBlock,
to ColorName.
// Bind the data source to the TextBox control's Text dependency property
myText.SetBinding(TextBlock.TextProperty, myBinding);
In the Create a binding section, the button is red because its Background property is bound to
a string property with the value "Red". This string value works because a type converter is
present on the Brush type to convert the string value to a Brush.
Adding this information to the figure in the Create a binding section looks like this.
[ValueConversion(typeof(Color), typeof(SolidColorBrush))]
public class ColorBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Color color = (Color)value;
return new SolidColorBrush(color);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
Once your ItemsControl is bound to a data collection, you may want to sort, filter, or group
the data. To do that, you use collection views, which are classes that implement
the ICollectionView interface.
Because views do not change the underlying source collections, each source collection can
have multiple views associated with it. For example, you may have a collection of Task objects.
With the use of views, you can display that same data in different ways. For example, on the
left side of your page you may want to show tasks sorted by priority, and on the right side,
grouped by area.
1. We create the data in the app.cs. public ObservableCollection<AuctionItem> AuctionItems { get; set; } = new
ObservableCollection<AuctionItem>();
AuctionItems.Add(camera);
AuctionItems.Add(snowBoard);
AuctionItems.Add(insideCSharp);
AuctionItems.Add(laptop);
AuctionItems.Add(setOfChairs);
AuctionItems.Add(myDvdCollection);
AuctionItems.Add(tvDrama);
AuctionItems.Add(squashRacket);
6.8 Sorting
As mentioned before, views can apply a sort order to a collection. As it exists in the underlying collection, your data may or
may not have a relevant, inherent order. The view over the collection allows you to impose an order, or change the default
order, based on comparison criteria that you supply. Because it's a client-based view of the data, a common scenario is that
the user might want to sort columns of tabular data per the value that the column corresponds to. Using views, this user-
driven sort can be applied, again without making any changes to the underlying collection or even having to requery for the
collection content. For an example, see Sort a GridView column when a header is clicked (.NET Framework).
The following example shows the sorting logic of the "Sort by category and date" CheckBox of the app
UI in the What is data binding section.
<Window.Resources>
<DataTemplate x:Key="personTemplate">
<Border BorderBrush="Green"
BorderThickness="10">
<StackPanel Margin="4">
<TextBlock Foreground="Red"
FontSize="20"
Text="{Binding Name}"
TextAlignment="Center" />
<TextBlock Foreground="Black"
FontSize="16"
Text="{Binding Age}"
TextAlignment="Right" />
</StackPanel>
</Border>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="150" />
<RowDefinition Height="150" />
<RowDefinition Height="150" />
<RowDefinition Height="150" />
</Grid.RowDefinitions>
<ListBox Grid.Row="0"
x:Name="_list"
HorizontalContentAlignment="Stretch"
ItemTemplate="{StaticResource personTemplate}" />
To see the changes in the view, a class entity like Person has to implement :
class Person : InotifyPropertyChanged
{
public string Name { get; set; }
public int Age { get; set; }
To see changes in a collection in the view the collection has to inherent from ObservableCollection
XAML Integration
2.2 Databinding
Dependency properties can be set indirectly via databinding. This can use the binding object notation but, most
commonly, the binding expression extension is used, as shown in Listing 2–3.
Listing 2–3.
<MyDependencyObject MyProperty="Hello!">
<Button />
</MyDependencyObject>
2.4 Styling
<Style x:Key="myButtonStyle">
<Setter Property="Control.Background" Value="Blue" />
</Style>
...
<Button Style="{StaticResource myButtonStyle}" />
<Window x:Class="MvvmWpfApp.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModel="clr-namespace:MvvmWpfApp.ViewModel;assembly=MvvmWpfApp.ViewModel"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<viewModel:SampleViewModel x:Key="sampleViewModel1" />
<viewModel:SampleViewModel x:Key="sampleViewModel2" />
</Window.Resources>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<Button Name="button1" />
<Button Name="button2" />
</StackPanel>
</StackPanel>
</Grid>
</Window>
In Listing 2–11, button1 and button2 will inherit their DataContext from their parent StackPanel. In
turn, that StackPanel inherits its DataContext from further up the logical tree, specifically from the Grid
control, whose DataContext has been explicitly set to sampleViewModel1 (via a StaticResource binding).
However, the DataContext of button3’s and button4’s parent has been overridden to reference
sampleViewModel2, so these two controls will also have a similar DataContext.
2.11 Advanced DataBinding
BindingGroupName
You can group bindings together and encapsulate the access of a number of different, but related,
bindings. Applications of this parameter are typically related to validation.
<TextBox Text="{Binding Path=myTextProperty, BindingGroupName=myBindingGroup}" />
BindsDirectlyToSource
When using a derivative of DataSourceProvider, such as ObjectDataProvider (which is covered later in
this chapter), you are binding to the underlying data via a provider. If you wish to bind to the provider
itself, you can set BindsDirectlyToSource to true, to override the default behavior.
<TextBox Text="{Binding Path=myDataSourceProvider, BindsDirectlyToSource=true}" />
ElementName
The source of bindings can be dependency properties, as we have seen. The corollary to this is that a
control may bind one of its properties to that of another control. In order to do this, the ElementName
parameter is specified to reference a specific control that is currently in scope.
<TextBox Text="Hello!" Name="textBox1" />
<TextBox Text="{Binding ElementName=textBox1, Path=Text}" />
FallbackValue
There are situations where a binding will succeed at compile time, but fail at runtime. Failure should
always be considered part of an application, and such circumstances need to be handled gracefully in
order to maintain a positive user experience. Users don’t expect software to be perfect, but they view
uncontained failure negatively and will treat your application very differently if messy failures are
endemic. Use the FallbackValue option to present your users with a friendly error message. If no
FallbackValue is specified, binding failure results in the default value for the type which, in the case of
string values, is the empty string.
Your event handlers should reside in the code-behind file and look similar to this:
private void OnSourceUpdated(object sender, DataTransferEventArgs args)
NotifyOnValidationError
Validation is covered in Chapter 6, and the NotifyOnValidationError binding property is one method of handling validation
in WPF/Silverlight using the MVVM architecture.
<TextBox Text="{Binding Path=myTextProperty, NotifyOnValidationError=true}" Validation.Error="OnValidationError" />
Path
We have used the Path parameter extensively so far; its use is no secret. It is not strictly a required
parameter: with the DataContext set, either explicitly or by being passed down to the contained children, you can bind to
the DataContext by not specifying a path at all:
Similarly, the Path parameter doesn’t need to be named if no other parameters are used in the
binding expression:
You can also use the dot notation (.) to drill down into subproperties on the bound object:
If you have an indexed property, you can specify the index value as part of the Path:
Collection views, which expose the concept of a current item, can be bound using the slash notation
(/):
<TextBox Text="{Binding Path=myCollectionView/}" />
<Window xmlns:viewModel="clr-namespace:BusinessModel;assembly=MyBusinessModel"
…>
<Window.Resources>
<viewModel:BusinessObject x:Key="myObject" />
</Window.Resources>
<TextBox Text="{Binding Path=MyTextProperty, Source={StaticResource myObject}}" />
</Window>
Source, however, references an object absolutely, whereas it can be useful to reference an object
relative to the binding target. The most common use is to bind to a property to another property on the same object:
This example binds the Text property to the Foreground property of the TextBox (it binds to itself, so to speak). The
resulting text will be the name of the color of the text written in that same color.
StringFormat
Just like the String.Format method, StringFormat applies a string formatting expression to the binding
value before rendering the whole string to the view.
<TextBlock Text="{Binding Path=CurrentPrice, StringFormat='{0:c}'}" />
This example will output the CurrentPrice property (a decimal value) as the currently specified
culture’s currency value.
If a Converter is specified on the binding, in addition to the StringFormat, the Converter is applied first.
TargetNullValue
Whereas FallbackValue is used when the binding fails, TargetNullValue is used when the source of the
binding is null. It is useful for specifying default display values for null inputs.
<TextBox Text="{Binding Path=FirstName, TargetNullValue='Please enter your first name…'}" />
UpdateSourceExceptionFilter
As with NotifyOnValidationError, UpdateSourceExceptionFilter is used in data validation scenarios as
covered in Chapter 6.
<TextBox>
<TextBox.Text>
<Binding Path="FirstName" UpdateSourceExceptionFilter="ExceptionHandler">
<Binding.ValidationRules>
<ExceptionValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
UpdateSourceTrigger
There are three possible values—besides default—for the UpdateSourceTrigger enumeration.
PropertyChanged updates the binding source as soon as the target property’s value has changed.
LostFocus updates the binding source when the target control loses focus. Explicit doesn’t
automatically update the binding source; instead, it manually calls the UpdateSource method on the
BindingExpression. By default, the TextBox’s Text property has an UpdateSourceTrigger of LostFocus,
while most other controls default to PropertyChanged. Sometimes, you will want to override the TextBox’s default to
update the source as soon as the property is changed: that is, whenever the user types a new value into the textbox.
<TextBox Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged}" />
XPath
If you are binding directly to XML data rather than object data, the Path property is replaced by the XPath property. XPath
is the XML Path language and is used to query XML data. You can construct XPath queries and set them to the XPath
parameter to bind to that data. XML databinding is outside of the scope of this book.
<TextBox Text="{Binding XPath=/Author[@FirstName='Gary' and @LastName='Hall']}" />
Data Conversion
IValueConverter Interface
The IValueConverter specifies two methods that must be implemented:
Converter={StaticResource myBooleanToVisibilityConverter},
ConverterParameter={x:Static windows:Visibility.Collapsed}}" />
object value:
The value that the binding source or target produces. It is an object
because the IValueConverter interface does not know what type you will be using,
so it will have to be cast to the object that’s applicable.
True/false/ taken from ShowText
• Type targetType:
This is the type the binding target (or binding source in
ConvertBack) requires. It allows you to target a number of different binding targets
with a single IValueConverter implementation.
Boolean/Visibility/String/ etc
• object parameter:
ConverterParameter is a binding expression parameter. You
can specify this parameter on a per-binding basis to further customize the
outcome of your converter.
Taken from ConverterParameter: Collapsed;
• CultureInfo culture:
Many different types require culture-specific formatting.
Currencies are a prime example of this, and have myriad variations depending on
locale. The euro, for instance, is represented with at least three different notations.
MultiValueConverter Interface
This coverter is the same as IValueConverter but instead it takes an array
<DataTemplate x:Key="itemTemplate">
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
DisplayMemberPath binds to one property of the class that feeds the collection without the need to specify
the DataTemplate
<Window.Resources>
<local:GreekGods x:Key="greekGods" />
<DataTemplate x:Key="itemTemplate">
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</Window.Resources>
<Border Margin="25"
Padding="5"
BorderBrush="RoyalBlue"
BorderThickness="2">
<StackPanel Orientation="Horizontal">
<ItemsControl Name="itemsControl1"
Width="150"
ItemTemplate="{StaticResource itemTemplate}"
ItemsSource="{StaticResource greekGods}" />
<ItemsControl Name="itemsControl2"
Width="150"
DisplayMemberPath="RomanName"
ItemsSource="{StaticResource greekGods}" />
</StackPanel>
</Border>
</Window>