CodeProject: WPF: A Beginner's Guide - Part ...

来源:百度文库 编辑:神马文学网 时间:2024/06/13 06:05:29
Preface And Thanks
I am a .NET programmer, but a busy one, I do VB .NET and C#, ASP .NET / Winforms / WPF / WCF Flash Silverlight the lot. Basically I keep my toe in. But when I started writing this article series I naturally chose my favourite language (which happens to be C#). I since got an email from an individual who requested that I publish this series with source code in VB .NET and C#. I simply stated I didn't have time. So this individual (Robert Ranck) volunteered to help out, and do the translation to VB .NET, based on my orginal C# projects
So for that and the subsequent VB .NET projects that you will find here I ask you to thank Robert Ranck. Cheers Robert, your contributions will surely make this series more open to all .NET developers.
And another thanks also goes outKarl Shifflett (AKA the blog/article machine, also known as the Molenator) for answering my dumb VB .NET questions. And I'd also like to mention that Karl has just started a more advanced series of WPF articles (which at present will be in VB.NET, but will hopefully appear in C# as well). Karls new series will be excellent and I urge you all to encourage Karl on this series. Its not easy obligating ones self to write an entire series in one language let alone 2. Karls 1st article is locatedright here, have a look for yourself. Personally I love it.
Introduction
This article is the 5th in my series of beginners articles for WPF. In this article we will discuss databinding. The proposed schedule for this series will still be roughly as follows:
LayoutXAML vs Code / Markup Extensions And ResourcesCommands And EventsDependency Properties (previous article) DataBinding (this article)Styles/Templates
In this article I'm aiming to cover, is a brief introduction into the following:
The general idea behind databindingDataContextBasic databinding conceptsDatabinding syntaxDatabinding to UI elementsDatabinding to xmlDatabinding to collectionsDatabinding value convertorsDatabinding validation
I will NOT be covering the following collection based binding areas, so if you want to know more about these you'll have to do a bit of extra research using the links provided (see i'm 1/2 ok, at least I researched the correct links for you)
SortingFilteringGroupingRecord ManipulationMaster/Detail
Databinding is actually not that new (ok how its done in WPF is new) but we have has binding in ASP .NET and Winforms for some time now. WPF has borrowed from both of these to create a really really good binding framework. But what is this binding stuff, for those of you that have never heard of it.
Well basically binding allows UI Elements to obtain their data either from other UI Elements or business logic objects/classes. So in theory its very simply, we have a source that provides a value, and we have a target that wants to use the sources value, and we kind of glue them together using binding.
A typical binding arrangement is as follows:

Typically, each binding has these four components: a binding target object, a target property, a binding source, and a path to the value in the binding source to use.
The target property must be aDepenedency Property (which I've just covered). Most UIElement properties are dependency properties and most dependency properties, except read-only ones, support data binding by default.
That's a very simplified version of whats going on in binding.
Of course to facilitate these binding operations there are many seperate considerations and bits of syntax that need to be considered. In the next sub sections you will look at some (no not all, i'd be here all year) of the binding syntax and ideas/approaches to creating happy bindings.
There is one important thing to know before we get into the ins and outs of Databinding, and that is the DataContext property, that every FrameworkElement has. DataContext is a concept that allows elements to inherit information from their parent elements about the data source that is used for binding, as well as other characteristics of the binding, such as the path. DataContext can be set directly to a common language runtime (CLR) object, with the bindings evaluating to properties of that object. Alternatively, you can set the data context to a DataSourceProvider object.
This dependency property inherits property values. If there are child elements without other values for DataContext established through local values or styles, then the property system will set the value to be the DataContext value of the nearest parent element with this value assigned.
In XAML, DataContext is most typically set to as a Binding declaration. You can use either property element syntax or attribute syntax. And is normal set something like this
............
You can also use code to set DataContext, simply by using a .DataContext =
Another thing to note is that if some object that inherits from a parents DataContext ommits which fields it will use to bind to, such as

This means that the entire object that is used as its parents DataContext will be used to assign to the Tag property
Before we can proceed onto looking at the nitty griity of databinding there are several key areas which we need to cover first. Namely
Direction of the data flow What triggers source updates
So we'll just spend a little bit of time on these 2 subjectsDirection Of The Data Flow
As shown above in thethe general idea behind databinding section, flow of binding could be 2 way. There are several possibilities that can be configured when using databinding. These are controlled using theBinding.Mode values:
OneWay binding causes changes to the source property to automatically update the target property, but changes to the target property are not propagated back to the source property. This type of binding is appropriate if the control being bound is implicitly read-only. TwoWay binding causes changes to either the source property or the target property to automatically update the other. This type of binding is appropriate for editable forms or other fully-interactive UI scenarios. OneTime causes the source property to initialize the target property, but subsequent changes do not propagate. This means that if the data context undergoes a change or the object in the data context changes, then the change is reflected in the target property. This type of binding is appropriate if you are using data where either a snapshot of the current state is appropriate to use or the data is truly static. OneWayToSource is the reverse of OneWay binding; it updates the source property when the target property changess. Default causes the default Mode value of target property to be used
Use theBinding.Mode property to specify the direction of the data flow. To detect source changes in one-way or two-way bindings, the source must implement a suitable property change notification mechanism such asINotifyPropertyChanged. For an example, see How to: Implement Property Change Notification.
Change notification is such an important lesson to learn in databinding that we need to look at that right now. So lets have a look at an example of using this interfaceINotifyPropertyChanged.
To support OneWay or TwoWay binding to enable your binding target properties to automatically reflect the dynamic changes of the binding source, your class needs to provide the proper property changed notifications, this is whereINotifyPropertyChanged is used.
using System.ComponentModel;namespace SDKSample{// This class implements INotifyPropertyChanged// to support one-way and two-way bindings// (such that the UI element updates when the source// has been changed dynamically)public class Person : INotifyPropertyChanged{private string name;// Declare the eventpublic event PropertyChangedEventHandler PropertyChanged;public Person(){}public Person(string value){this.name = value;}public string PersonName{get { return name; }set{name = value;// Call OnPropertyChanged whenever the property is updatedOnPropertyChanged("PersonName");}}// Create the OnPropertyChanged method to raise the eventprotected void OnPropertyChanged(string name){PropertyChangedEventHandler handler = PropertyChanged;if (handler != null){handler(this, new PropertyChangedEventArgs(name));}}}}
And heres a VB .NET version
Imports System.ComponentModel' This class implements INotifyPropertyChanged' to support one-way and two-way bindings' (such that the UI element updates when the source' has been changed dynamically)Public Class PersonImplements INotifyPropertyChangedPrivate personName As StringSub New()End SubSub New(ByVal Name As String)Me.personName = NameEnd Sub' Declare the eventPublic Event PropertyChanged As PropertyChangedEventHandlerImplements INotifyPropertyChanged.PropertyChangedPublic Property Name() As StringGetReturn personNameEnd GetSet(ByVal value As String)personName = value' Call OnPropertyChanged whenever the property is updatedOnPropertyChanged("Name")End SetEnd Property' Create the OnPropertyChanged method to raise the eventProtected Sub OnPropertyChanged(ByVal name As String)RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name))End SubEnd Class
To implementINotifyPropertyChanged you need to declare the PropertyChanged event and create the OnPropertyChanged method. Then for each property you want change notifications for, you call OnPropertyChanged whenever the property is updated.
I can not tell you how important theINotifyPropertyChanged interface is, but believe me its very very important, and if you plan to use Binding in WPF, just get used to using theINotifyPropertyChanged interface.
What Triggers Source Updates
Bindings that are TwoWay or OneWayToSource listen for changes in the target property and propagate them back to the source. This is known as updating the source. For example, you may edit the text of a TextBox to change the underlying source value. As described in the last section, the direction of the data flow is determined by the value of theBinding.Mode property of the binding.
However, does your source value get updated while you are editing the text or after you finish editing the text and point your mouse away from the TextBox? TheBinding.UpdateSourceTrigger property of the binding determines what triggers the update of the source. The options available are as follows :
The following table provides an example scenario for eachBinding.UpdateSourceTrigger value using the TextBox as an example:
UpdateSourceTrigger value When the Source Value Gets Updated
LostFocus (default for TextBox.Text) When the TextBox control loses focus
PropertyChanged As you type into the TextBox
Explicit When the application calls UpdateSource
There are many properties that may be used within theBinding class, as such I will not have time to cover all of them, though I shall attempt to go through the most common buts of syntax. As most binding will usually be set in XAML I will be concentrating on the XAML syntax, though it should be noted that anything that can be done in XAML can also be done in C#/VB .NET code behind.
Ok so lets have a look at the basic syntax (we will cover more advanced stuff in the sections below).
The most basic form of binding if to create a binding that binds to a value of an existing element (this is covered in more detail below also) I just wanted to introduce the syntax and go back and show you how to do theBinding.Mode andBinding.UpdateSourceTrigger stuff first.
So here is probably one of the simplist Bindings that you will see. This example has 2 buttons, the 1st button (btnSource) has a Yellow Background property. The 2nd button uses the 1st button (btnSource), as the source for a Binding where the 1st button (btnSource) Background value is being used to set the 2nd buttons Background.

So that'd fairly simple right. But I just wanted to go back and have a quick look at how we could also use theBinding.Mode andBinding.UpdateSourceTrigger properties within the binding sytnax.
Well as it turns out, its fairly easy, we just add the extra property and its desired value into the binding expression such as

An Important Note :
Recall frompart 2 that I mentioned that Binding was a markupMarkupExtension. As such the XAML parser knows how to treat the { } sections. But really this is just shorthand, that can (if you prefer) be expressed using the longer more verbose syntax as shown below.

This is a decision you will have to make yourself, me personally I prefer the { } syntax, though you dont get any intellisense help within Visual Studio if you do use the {} syntax.
When you set out to set up a Binding there are several different things you need to consider
What property do I want to bind to What property should we bind from Does it need to be OneWay or TwoWay etc etc Binding. If it needs to be a TwoWay/OneWayToSource Binding, was the source property a Dependency Property. It has to be to carry out TwoWay/OneWayToSource Binding
Once you know or have considered all this, its really as easy as ABC. As part of the demo solution, you will find a project entitled "BindingToUIElements" which when run, will look like the following:

This simple demo application shows 3 different bindings going on. Ill briefly discuss each of these now.
1. Simply Element Binding (Default Mode)
This simple example uses the 1st buttons Background as the source value for the other 2 Buttons Background
The code for which is as follows: