The Binding class has more properties than we have space to discuss here, but we'll cover the most important ones in detail shortly, and briefly look at other notable properties momentarily. The Binding class is the top-level class in each binding, but internally it uses a lower-level class that maintains the connection between the binding source and binding target.
The BindingExpression class is that underlying object. When using MVVM, developers do not typically access this inner class, as we tend to keep our functionality in our View Models. However, if we are writing custom controls, then it can be useful to be aware of it.
It can be used to programmatically update the associated binding source in certain circumstances and we'll find out about that later in the chapter. For now, let's focus on what the Binding class can do for us.
In .NET 4.5, a great new property was added to the Binding class. The Delay property enables us to specify an amount of time in milliseconds with which to delay the update of the binding source after a change has been made to the binding target property value.
This is really useful if we are performing some heavy computational validation or other processing dependent upon the user's input in a TextBox element for example. To clarify this functionality further, this delay is actually restarted each time the data bound property value changes, or each key press in our example. It is typically used to update the binding source in chunks, each time the user pauses, or completes typing, somewhat like buffering:
<TextBox Text="{Binding Description, UpdateSourceTrigger=PropertyChanged, Delay=400}" />
The FallbackValue property is another useful property when it comes to performance. In order to return a value from each binding, the WPF Framework does up to four things. The first is to simply validate the target property type with the data bound value. If successful, it will then try to resolve the binding path.
Most of the time, this will work, but if not, it will then attempt to find a converter to return the value. If it can't find one, or the located converter returns the DependencyProperty.UnsetValue value, it will then look to see if the FallbackValue property has a value to provide it with. If there is no fallback value, then a lookup is required to find the default value of the target Dependency Property.
By setting the FallbackValue property, we can do two things to improve performance, albeit in a slight way. The first is that, it will stop the WPF Framework from performing the lookup of the default value of the target Dependency Property. The second is that it will prevent trace statements from being fed to the Output window in Visual Studio and to any other trace outputs that have been setup.
The TargetNullValue property is similar to the FallbackValue property in that it enables us to provide some output when there is no data bound value from the binding source. The difference is that the FallbackValue property value is output when a data bound value cannot be resolved, while the TargetNullValue property value is used when the successfully resolved data bound value is null.
We can use this functionality to display a more humanized value than null, or even to provide a default message in our textbox controls for example. To do this, we could set our data bound string properties to null and set a suitable value to the TargetNullValue property:
<TextBox Text="{Binding Name, TargetNullValue='Please enter your name'}" />
Of course, this message will actually appear in the TextBox control, so it's not an ideal way of providing this functionality. We'll see a better example of this later in the book, but now, let's continue our exploration of the Binding class.
If we have any properties in our View Model that access their data asynchronously, or if they are calculated by a heavy computational process, then we need to set the IsAsync method to True on the binding:
<Image Source="{Binding InternetSource, IsAsync=True, FallbackValue='pack://application:,,,/CompanyName.ApplicationName; component/Images/Default.png'}" />
This stops the UI from being blocked while waiting for the data bound property to be calculated, or otherwise resolved. Until the binding source is resolved, the fallback value is used, if set, or the default value will be used otherwise. In this example, we are providing a default image to be displayed until the actual image is downloaded from the internet and the binding source is resolved.
Another useful property of the Binding class is the StringFormat property. As the name hints, this uses the string.Format method internally to format our data bound text output. There are, however, a few caveats to using this functionality. The first is that we can only use a single format item, that is represented by the single data bound value in a normal binding. We'll find out how to use multiple values later in the chapter.
Secondly, we need to declare our format carefully, as curly brackets are used by the markup extensions and we cannot use the double quote characters ("), as the binding is already declared within double quotes. One solution is to use single quotes to surround our format string:
<TextBlock Text="{Binding Price, StringFormat='{0:C2}'}" />
Another option is to escape the format by preceding it with a pair of curly brackets:
<TextBlock Text="{Binding Price, StringFormat={}{0:C2}}" />
Most of the useful binding properties have now been discussed here, but it should be noted that there are a number of properties in the Binding class that are not typically used when building a WPF application with MVVM. This is because they involve event handlers and we do not normally implement event handlers when using MVVM.
For example, the three NotifyOnSourceUpdated, NotifyOnTargetUpdated and NotifyOnValidationError properties relate to the raising of the Binding.SourceUpdated, Binding.TargetUpdated and Validation.Error Attached Events.
Likewise, the three ValidatesOnDataErrors, ValidatesOnExceptions, ValidatesOnNotifyDataErrors and ValidationRules properties all relate to the use of the ValidationRule class. This is a very UI-related way of validating, but this puts our business logic right into our Views component.
When using MVVM, we want to avoid this blending of components. We therefore tend to work with data elements rather than UI elements, and so we perform these kind of duties in our Data Model and/or View Model classes instead. We'll see this in Chapter 9, Implementing Responsive Data Validation, later in the book, but now let's take a deeper look at the most important properties of the Binding class.