WPF: Asynchronous Data Binding Using IsAsync and Delay
**
**
**
**
INTRODUCTION: IsAsync
Most system designs will mean that data needs to be obtained from a view using it is presented. If this is a long process, a common technique is to present a busy indicator whilst data is collected. The View might be presented bare, the busy indicator is hidden and the data presented once it arrives.
Occasionally, part of the content might not be critical and it might be attractive to obtain most of the data, show the view and later add the lower priority data.
A classic sort of an example of this pattern would be how some web pages download text and show it, only later presenting images.
WPF has the IsAsync property for a binding. The effect is that the binding doesn't wait for a value to be returned from the bound property getter before continuing.
The get is called and control immediately returns.
Images are a "classic" area where one would use IsAsync.
There is no free meal here though and the object must either not have thread affinity or be coerced to the UI thread, PropertyChanged event must be raised on the UI thread. Whilst the property has not been provided, usual rules also apply on the binding and it will return null. You can, therefore, show an initial default value using FallBackValue.
DEMO: Synchronous binding
Here is the .cs file.
public partial class AsyncBinding : UserControl, INotifyPropertyChanged
{
public AsyncBinding()
{
InitializeComponent();
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string txt)
{
PropertyChangedEventHandler handle = PropertyChanged;
if (handle != null)
{
handle(this, new PropertyChangedEventArgs(txt));
}
}
#endregion
private string firstname;
public string FirstName
{
get { return firstname; }
set
{
firstname = value;
OnPropertyChanged("FirstName");
}
}
private string address;
public string Address
{
get
{
Thread.Sleep(5000);
return address;
}
set
{
Thread.Sleep(5000);
address = value;
OnPropertyChanged("Address");
}
}
private string phone;
public string Phone
{
get { return phone; }
set
{
phone = value;
OnPropertyChanged("Phone");
}
}
private void ThisWindow_Loaded(object sender, RoutedEventArgs e)
{
FirstName = "Ryan";
Address = "USA";
Phone = "4563525234523";
}
}
Inside addresses set/get a block in Thread.Sleep(). While running the application, we can see a delay in loading the elements in the UI.
DEMO: IsAsync
Added IsAsync= true inside address property binding. See the result.
Initial state
Initially, we got data in all fields except address without any delay. After a few seconds, address field has been populated in the different thread.
After 5000 milliseconds.
INTRODUCTION: Delay
Delay simply introduces a delay before the getter is called. It is often used to spread processing load or (rarely) where you know in advance a value will vary rapidly for a short period of time.
In some cases, you might have some logic inside a set block of a property that is bound to a TextBox.Text property. That logic will be called when the user enters each character if UpdateSourceTrigger=PropertyChanged.
DEMO: Delay
For a delay demonstration, we have commented the Thread.Sleep() in the get/set block of the address property and in the XAML we can see our address property bound with two Text Boxes. We have added one delay inside the address property highlighted in the image below.
private string address;
public string Address
{
get
{
// Thread.Sleep(5000);
return address;
}
set
{
// Thread.Sleep(5000);
address = value;
OnPropertyChanged("Address");
}
}
Once we type into the address1 text box, that will wait for 500 milliseconds to reflect the changes. After that time address2 will be populated.
Initial state
After 500 milliseconds
Conclusion
Two alternative mechanisms for asynchronous binding have been presented: IsAsync mainly for binding large resources and Delay is used to avoid calling downstream logic too soon for rapidly changing values.