Data Binding C# Help

In the previous chapter you saw a few features of data binding when styling the ListBox. But of course there is a lot more. WPF data binding takes another huge step forward compared to Wmdows Forms. This section gives you a good start in data binding with WPF and discusses these topics:

  1. Overview
  2. Binding with XAML
  3. Simple object binding
  4. Object data provider
  5. List binding
  6. Binding to XML.

Overview

With WPF data binding, the target can be any dependency property of a WPF element, and every property of a CLR object can be the source. Because a WPF element is implemented as a .NET class, every WPF element can be the source as well. for the connection between the source and the target. The Binding object defines the connection.

Figure 35-1

Binding supports several binding modes between the target and source. Binding can be one-way, where the source information goes to the target, but if the user changes information in the user interface, the source does not get updated. For updates to the source, two-way binding is required.

The following table shows the binding modes and their requirements.

Capture

Binding with XAML

A WPF element can not only be the target for data binding, it can also be the source. You can bind the source property of one WPF element to the target of another WPF element .

The following code example uses the funny face created earlier, which is built up from WPF shapes and binds it to a slider, so you can move it across the window. The Slider is the source element with the name slider. The property Value gives the actual value of the slider position. The target for data binding is the inner Canvas element. The inner Canvas element with the name FunnyFace contains ail the shapes needed to draw the funny face. This canvas is contained within an outer Canvas element, so it is possible to position this canvas within the outer canvas by setting the attached properties. The attached property Canvas. Left is set to the Binding markup extension. In the Binding markup extension, the ElementName is set to slider to reference the WPF slider element, and the Path is set to value to get the value from the Val ue property.

Capture

When running the application, you can move the slider and make the funny face move, as you can see.

Instead of defining the binding information with XAML code, as was done in the preceding code with the Binding metadata extension, you can do it with code behind. Have one more look at the XAML version, of binding:

Capture

With code behind you have to create a new Binding object and set the Path and Source properties. The source property must be set to the source object; here, it is the WPF object slider. The Path is set to a PropertyPath instance that is initialized with the name of the property of the source object, Value.

Figure 35-2

Figure 35-3

With the target, you can invoke the method SetBinding () to define the binding. Here, the target is the Canvas object with the name FunnyFace. The method SetBinding () requires two parameters: the first one is a dependency property and the second one is the binding object. The Canvas. Left property should be bound, so the dependency property of type DependencyProperty can be accessed with the Canvas. LeftProperty field:

Capture

You can configure a number of binding options with the Binding class, as described in the following table.

Capture

Capture

Simple Object Binding

For binding to CLR objects, with the .NET classes you just have to define properties, as shown in this example with the class Book and the properties TitIe, publisher, Isbn, and Authors:

Capture

Capture

In the user interface,several label sand TextBox controls are defined to display book information. Using Binding markup extensions, the TextBox controls are bound to the properties of the Book class.With
the Binding markup extension nothing more than the Path property is defined to bind it to the property of the Book class.There’s no need to define a source because the source is defined by assigning the DataContext, as you can see in the code behind that follows. The mode is defined by its default with the TextBox element, and this is two-way binding.

Capture

Capture

With the code behind, anew Book object is created, and the book is assigned to the DataContext property of the Grid control. DataContext is a dependency property that is defined with the base class FrameworkElement. Assigning the DataContext with the Grid control means that every element in the Grid control has a default binding to the same data context.

Capture

After starting the application, you can see the bound data, as shown.

Figure 35-4

To demonstrate the two-way binding (changes to the input of the WPF element are reflected inside the CLR object), the OnOpenBookDialog () method is implemented. This method is assigned to the Click event of the book Button, as you can see in the XAML code. When implemented a message box pops up to show the current title and ISBN number of the bookl object. Figure 35-5 shows the output from the message box after a change to the input was made during runtime.

Figure 35-5

Object Data Provider

Instead of defining the object in code behind, you can define an object instance with XAML. To make this possible, you have to reference the namespace with the namespace declarations in the XML root element. The XML attribute xmlns: src=” clr-namespace: Wrox. ProCsharp. WPF’ assigns the .NET ./ namespace Wrox. ProCSharp. WPFto the XML namespace alias src.

One object of the Book class is now defined with the Book element inside the Window resources. By assigning values to the XML attributes Ti t Le and Publ isher, you set the values of the properties from .:. the Book class. x: Key=’ the Book ” defines the identifier for the resource so that you can reference the book object. In the TextBox element, now the Source is defined with the Binding markup extension to reference the theBook resource.

Capture

Instead of defining the object instance directly within XAMLcode, you can define an object data provider that references a class to invoke a method. For use by the ObjectDataProvider, it’s best to create a factory class that returns the object to display, as shown with the BookFactory class:

Capture

The ObjectDataProvider element can be defined in the resources section. The XML attribute ObjectType defines the name of the class; with MethodName you specify the name of the method that is
invoked to get the book object:

Capture

The properties you can specify with the ObjectDataProvider class.are listed in the following table.

Capture

List Binding

Binding to a list is more frequently done than binding to simple objects. Binding to a list is very similar to binding to a simple object. You can assign the complete list to the DataContext from code behind, or you can use an ObjectDataProvider that accesses an object factory that returns a list. With elements that support binding to a list (for example, a ListBox), the complete list is bound. With elements that support binding to just one object (for example, a TextBox), the current item is bound.

With the BookFactory class, now a list of Book objects is returned:

Capture

In the WPF code-behind constructor of the class window1 a BookFactory is instau,tiated and the method GetBooks () is invoked to assign the Book array with the DataContext of the Window1instance:

Capture

Capture

Capture

Because the window has the Book array assigned to the DataContext, and the ListBox isplaced withinthe Window, the List.BOX shows allbooks with the default template, as illustrated.

Figure 35-6

For a more flexiblelayout of the ListBox, you have to define a template, as was discussed in the previous chapter for ListBox styling. The ItemTernplate contained in the style listBoxStyle defines a DataTemplate with a Label element. The content of the label is bound to the Title. The item template is repeated for every item in the list.

The ListBox element has the Style property assigned. ItemsSource is, as before, set to the default binding.

Figure 35-7

Master·Details Binding

Instead of just showing all the elements inside a list, you might want or need to show detail information about the selected item. It doesn’t require a lot of work to do this. You just have to define the elements to display the current selection. In the sample application, three Label elements are defined with the Binding markup extension set to the Book pro e~es Ti t Le, Publisher, and Isbn. Theres one important change you have to make to the Lis ox. By default, the labels are bound to just the first element of the list. Bysetting the ListBox prof- -rty IsSynchronizedWi thCurrentItem= ‘True’, the selection of the list box is set to the current item. In Figure 35-8 you can see the result; the selected item is shown in the detail section labels.

Capture

Capture

Figure 35-8

Value Conversion

The authors of the book are still missing in the output. If you bind the Authors property to a Label element, the ToString () method of the Array class is invoked, which just returns the name of the type. One solution to this is to bind the Authors property to a ListBox. For the ListBox, you can define a template for a specific view. Another solution is to convert the string array returned by the Authors property to a string and use the string for binding.

The class StringArrayConverter converts a string array to a string. WPF converter classes must implement the interface IVaI ueConverter from the namespace Sys tern. Windows. Oata. This interface . defines the methods Convert () and ConvertBack ( ) . With the StringArrayConverter, the Convert () method converts the string array from the variable value to a string by using the String. Join () method. The separator parameter of the Jqin () is taken from the variable parameter received with the Convert () method.

Capture

In the XAMLcode, the StringArrayConverter class can be declared as a resource for referencing it from the Binding markup extension:

Capture

For multiline output, a TextBlock element is declared with the TextWrapping property set to Wrap to make it possible to display multiple authors. In the Binding markup extension the Path is set to Authors, which is defined as a property returning a string array. The string array is converted from the resource  stringArrayConverter as defined by the Converter property. The Convert method of the converter implementation receives the ConverterParameter’, ‘as input to separate the authors:

Capture

It shows the book details, including authors.

Figure 35-9

Adding List Items Dynamically

What lf list items are added dynamically? The WPF element must be notified of elements added to the list.

In the XAMLcode of the Wl’F application, a Button element is added inside a StacJc’Panel. The Click event is assigned to the method OnAddBook ( ) :

Capture

In the method OnAddBook (), which implements the event handler code for the addBookButton, a new Book object is added to the list. If you test the application with the BookFactory as it is implemented now, there’s no notification to the WPF elements that a new object has been added to the list.

Capture

The object that is assigned to the DataContext must implement the interface INotifyCollectionChanged. This interface defines the CollectionChanged event that is used by the WPF application. Instead of implementing this interface on your own ,,with.a custom collection class, you can use the generic collection class ObservableCollection<T> that is defined with the namespace System. Collections. Obj ectModel in the assembly windowsEase as a new item is added to the collection, the new item immediately shows up in the ListBox.

Capture

Data Templates

In the previous chapter, you saw how controls can be customized with templates. You can also define a template for a data type, for example, the Book class. No matter where the Book class is used, the template defines the default look.

In the example, the DataTemplate is defined within the Window resources. The DataType property references the class Book from the namespace Wrox. ProCSharp. WPF.The template defines a border with two label elements contained in a stack panel. With the ListBox element you can see there’s no template referenced. The only property that is defined by the ListBox is ItemsSource with a value for the default Binding markup extension. Because the DataTemplate does not define a key, it is used by all lists containing Book objects. It shows the output of the application with the
data template.

Capture

Figure 35-10

In case you want to use a different data template with the same data type, you can create a data template selector.A data template selector is implemented in a class that derives from the base class
DataTemplateSelector.

Here a data template selector is implemented by selecting a different template based on the publisher. Within the window resources these templates are defined. One template can be accessed by the key name .CsharpTemplate; the other template has the key name WileyBookTemplate:

Capture

For selecting the template the class BooltDataTemplateSelector overrides the method SelectTemplate from the base class DataTemplateSelector. The implementation selects the template based on the Publisher property from the Book class:

Capture

For accessing the class BooltDataTemplateSelector from XAML code, the class is defined within the Window resources:

<src:BookDataTemplateSelector x:Key=”bookTemplateSelector” />

Now the selector class can be assigned to the ItemTemplateSelector property of the ListBox:

<ListBox ItemsSource=”{Binding}”
ItemTemplateSelector=” {StaticResource bookTemplateSelector}” />

When running the application, you can see different data templates based on the publisher, as shown.

Figure 35-11

Binding to XML

WPF data binding has special support for binding to XML data. You can use XmlDataProvider as a data source and bind the elements by using XPath expressions. For a hierarchical display, you can use
the TreeView control and create the view for the items by using the HierarchicalDataTemplate.

The following XML file containing Book elements is used as a source in the next examples:

Capture

Similarly to defining an object data provider, you can define an XML data provider. Both ObjectDataProvider and XrnlDataProvider are derived from the same base class, DataSourceProvider. With the XrnlDataProvider in the example, the Source property is set to reference the XML file books .XIIIl. The XPath property defines an XPath eXfre§.Sion to reference the XMLroot element Books. The Grid element references the XMLdata source with the DataContext property. With the data context for the grid, all Book elements are required for a list binding, so the XPath expression is set to Book. Inside the grid, you can find the ListBox element that binds to the default data context and uses the DataTemplate to include the title in TextBlock elements as items of the ListBox. Inside the grid, you can also see three Label elements with data binding set to XPath expressions to display the title, publisher, and ISBN numbers.

Capture

It shows the result of the XML binding.

Figure 35-12

If XML data should be shown hierarchically, you can use the Treeview control.

Binding Validation

Several options are available to validate data from the user before it is used with the .NET objects. These
options are:

  1. Handling exceptions
  2. Data error information
  3. Custom validation rules.

Handling Exceptions

One of the options demonstrated here is that the .NET class throws an exception if an invalid value is set as shown in the class SomeData.The property Value1 accepts only values larger or equal to 5 and smaller than 12:

Capture

In the constructor of the Windowl class, a new object of the class SOr.leDatais initialized and passed to the DataContext for data binding:

Capture

With simple data binding, here the Text property of a TextBox is bound to the Valuel property. If you run the application now and try to change the value to one that is not valid, you can verify that the value never changed by clicking the Submit button. WPF catches and igores the exception thrown by the set accessor of the property valuel.

Capture

To display an error as soon as the context of the input field changes, you can set the ValidatesOnException property of the Bindi~g markup extension to True. With an invalid value (as soon as the exception is thrown when the value should be set), the TextBox is surrounded by a red colored line as shown.

Figure 35-13

To return the error information in a different way to the user, you can assign the attached property ErrorTemplate that is defined by the Validation class to a template defining the UI for errors. Thenew template to mark the error is shown here with the key validationTemplate. The Control Template puts a red exclamation point in front of the existing control content.

Capture

The new look of the application is shown.

Figure 35-14

Another option for a custom error message is to register to the Error event of the Validation class. Here the property NotifyOnValidationError must be set to true.

The error information itself can be accessed from the Errors collection of the Validation class. To . display the error information in the Tool Tip of the TextBox you can create a property bigger as shown. The bigger is activated as soon as the HasError property of the Validation class is set to True. The bigger sets the ToolTip property of the TextBox.

Capture

Data Error Information

Another way to deal with errors is if the .NET object implements the interface lDataErrorlnfo.

The class SomeData is now changed to implement the interface lDataErrorlnfo. This interfaced the property Error and an indexer with a string argument: WithWPFvalidation during data binding, the indexer is called and the name of the property to validate is passed as the columnName argument With the implementation the value is verified if it is valid, and an error string is passed otherwise.

Here the validationisdone on the property Value2 thatisimplemented by using theC# 3.0simple property notation:

Capture

With a .NET entity class it would not be clear what an indexer would return; for example, what would you expect from an object of type Person calling an indexer? That’s why it is best to do an explicit implementation of the interface IDataErrorlnfo. This way this indexer can be accessed only by using the interface, and the .NET class could do a different implementation for other purposes.

If you set the property ValidatesOnDataErrors of the Binding classto true, theinterface IDataErrorlnfo isused during binding.Here, when the TextBox ischanged, thebinding mechanism invokes the indexer of the interfaceand passes Value2 to the columnName variable:

Capture

Custom Validation Rules

To get more control of the validation you can implement a custom validation rule. A class implementing a custom validation rule needs to derive from the base class validationRule. With the previous two examples, validation rules have been used as well. Two classes that derive from the abstract base class validationRule are DataErrorValidationRule and ExceptionValidationRule. DataErrorValidationRule is activated by setting the property ValidatesOnDataErrors and uses the interface IDataErrorlnfo; ExceptionValidationRule deals with exceptions and is activated by setting the property ValidatesOnException.

Here a validation rule is implemented to verify for a regular expression. The class RegularExpressionValidatiOnRule derives from the base class validationRule and overrides the abstract method Validate () that is defined by the base class. With the implementation, the RegEx class from the namespace System. Text. RegularExpressions is used to validate the expression defined by the Expression property.

Capture\

Instead of using the Binding markup extension, now the binding is done as a child of the TextBox. Text element. The bound object now defines an Email property that is implemented with the simple property syntax. The UpdateSourceTrigger property defines when the source should be updated. Possible options for updating the source are:

  1. When the property value changes, which would be every character that is typed by the user
  2. When the focus is lost
  3. Explicitly.

ValidationRules is a property of the Binding class that contains validationRule elements. Here the validation rule used is the custom class RegularExpressionValidationRule, where the Expression property is set to a regular expression that verifies if the input is a valid e-mail, and the ErrorMessage property that gives the error message in case the data entered to the TextBox is not valid:

Capture

Capture

Posted on October 31, 2015 in Advanced WPF

Share the Story

Back to Top