|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionConventionally, in Windows Forms and ASP.NET applications, data binding was primarily used for populating elements on the screen with information; there was simple data binding for displaying single values, and complex data binding for displaying and formatting a collection of data. The beauty of data binding is that you can populate the interface while writing little to no code. With data binding in WPF you can take data from almost any property of any object and bind it to almost any other dependency property of another object. In the first part of this two part series, I am going to cover the basics of data binding in WPF. In the second part, more advanced data binding concepts will be covered such as templates and varying the way information is displayed based on characteristics of the data. For both of these parts, you will need to have a basic understanding of WPF. PrerequisitesThis article is written with the assumption that the reader has already achieved a basic understanding of the following WPF concepts:
BasicsIn its most basic form, data binding copies a value from a source object to a property on a destination object. The source property can be anything. The destination will be a dependency property. A key difference in binding to a WPF element property as the source and binding to another object type is that the WPF object has change notification; once binding has occurred with a WPF element property as a source, when the source changes, the destination property will automatically be updated. Let’s look at a couple of very simple WPF data binding expressions. <Window x:Class="Example00.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid >
<Grid.RowDefinitions >
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox Name="mySourceElement" Grid.Row="0" >Hello World</TextBox>
<TextBlock Grid.Row="1">
<TextBlock.Text>
<Binding ElementName="mySourceElement" Path="Text" />
</TextBlock.Text>
</TextBlock>
<TextBlock Text="{Binding ElementName=mySourceElement,Path=Text }" Grid.Row="2" />
</Grid>
</Window>
Example 00
As you might have guessed, when you run this example, it will display “Hello Word.” The text is displayed three times. The first instance of the text is displayed because it is the literal value assigned to the text box. The next two instances are in textboxes, and are the result of data binding. Both of the text boxes create a binding with the textbox named “
<Window x:Class="Example01.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Example 01" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions >
<RowDefinition Height="40px" />
<RowDefinition Height="40px" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Slider Name="fontSizeSlider" Minimum="5"
Maximum="100" Value="10" Grid.Row="0" />
<TextBox Name="SizeTextBox"
Text="{Binding ElementName=fontSizeSlider, Path=Value}" Grid.Row="1"/>
<TextBlock Text="Example 01"
FontSize="{Binding ElementName=SizeTextBox, Path=Text}" Grid.Row="2"/>
</Grid>
</Window>
Example 01
In this example, there are three elements bound together. A
Also, note that if you click in the text box and manually change its value, the slider and the text block will both update as soon as you tab out of the text box. The data appears to flow in both directions in this example (from the slider to the textbox, and from the textbox to the slider). This behavior of data binding is controlled through the binding mode. Binding ModesThe binding mode sets in which direction data will flow. Data usually flows from the source to the destination. There are five data binding modes.
The Controlling When Binding OccursBinding that occurs in a forward direction (from source to destination) occurs immediately. When you change the slider, the numeric value in the text box, or the combo box value, the changes occur to the text block immediately. But, you may have noticed that when you enter a numeric value into the text box, the slider does not update until the text box loses focus. Binding that occurs in the reverse direction doesn’t occur immediately, by default. The
Binding to Public Properties on Objects that are not ElementsSo far, we have looked at binding to WPF elements. When binding to a property that isn’t an element, the
* - Actually no runtime searching occurs. The If no source is defined in a binding expression, then the source is assumed to be the data context. When several elements are being bound to the same source object, the implicit use of the data context saves a lot of typing. Instead of specifying the data sources on all of the elements that bind to the same source, we can assign the source object to the data context of some parent object. <Window.Resources>
<local:Employee
x:Key="MyEmployee" EmployeeNumber="123" FirstName="John"
LastName="Doe" Department="Product Development" Title="QA Manager"
/>
</Window.Resources>
<Grid DataContext="{StaticResource MyEmployee}">
<TextBox Text="{Binding Path=EmployeeNumber}"></TextBox>
<TextBox Text="{Binding Path=FirstName}"></TextBox>
<TextBox Text="{Binding Path=LastName}" />
<TextBox Text="{Binding Path=Title}"></TextBox>
<TextBox Text="{Binding Path=Department}" />
</Grid>
Example 03
Binding to CollectionsDependency properties support single-value binding. For binding to a collection of objects, your destination object must derive from
You can bind to any collection that implements the For this example, the code is binding to a collection of <TextBox Text="{Binding Path=FirstName}" />
<TextBox Text="{Binding Path=LastName}" />
<TextBox Text="{Binding Path=Title}" />
<TextBox Text="{Binding Path=Department}" />
Example 04
When the selected item in the list is changed, the data context is automatically updated. When the If an element were programmatically inserted or removed from the collection after it is bound, the interface won’t update. To make the list automatically respond to insertions and deletions, the interface would need to be bound to a list that implements the Binding to DataTablesBinding to tables is similar to binding to a list. In WPF, you cannot bind directly to a Value ConversionSometimes, you will need to make a change to data that is being bound so that it is more appropriate for being displayed on the screen. For example, if your source data has a property that contains a path to an image, you would probably want to display the image instead of the image’s path. Value converters are responsible for performing this task. To create a value converter, declare a class that inherits from The
<Window.Resources>
<local:FarenheitToCelciusConverter x:Key="myTemperatureConverter" />
<local:TemperatureToColorConverter x:Key="myFRangeIndicator"
HotTemperature="80" ColdTemperature="65" />
<local:TemperatureToColorConverter x:Key="myCRangeIndicator"
HotTemperature="26.6" ColdTemperature="18.8" />
</Window.Resources>
<TextBox Name="txtFarenheit"
Foreground="{Binding Path=Text, ElementName=txtFarenheit,
Converter={StaticResource myFRangeIndicator}}"
/>
<TextBox Name="txtCelcius"
Text="{Binding UpdateSourceTrigger=PropertyChanged,
Path=Text,ElementName=txtFarenheit,
Converter={StaticResource myTemperatureConverter}}"
Foreground="{Binding Path=Text, ElementName=txtCelcius,
Converter={StaticResource myCRangeIndicator}}"
/>
Example 06
[ValueConversion(typeof(double), typeof(double))]
public class FarenheitToCelciusConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
string sourceValue = value.ToString();
double decimalValue = 0;
if (Double.TryParse(sourceValue, out decimalValue))
{
return (decimalValue - 32.0) * (5.0 / 9.0);
}
return value;
}
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
string sourceValue = value.ToString();
double decimalValue = 0;
if (Double.TryParse(sourceValue, out decimalValue))
{
return (decimalValue * (9.0 / 5.0)) + 32.0;
}
return value;
}
#endregion
}
Example 06 Value converter code
ValidationTo prevent a user from entering invalid data, your classes may contain logic to prevent invalid values from being set. But, if an exception is thrown when an invalid value is set, the user will not receive feedback explaining that a value is invalid. WPF will automatically suppress exceptions that occur during binding. To provide user feedback for validation problems, WPF has a facility named Validation Rules. One of the built-in validation rules is the <Binding Path="EventDate" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<ExceptionValidationRule />
</Binding.ValidationRules>
</Binding>
Example 07
You can create your own validation rules be inheriting from the If you wanted a list of all of the elements that have encountered validation errors during binding, walk through the form hierarchy, testing each element’s
In the Next Section…For the next part in this two part article series on data binding, I’ll cover more details of validation and rules, and will introduce data templates (for customizing how information is displayed in
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||