Welcome to Pete Brown's 10rem.net

First time here? If you are a developer or are interested in Microsoft tools and technology, please consider subscribing to the latest posts.

You may also be interested in my blog archives, the articles section, or some of my lab projects such as the C64 emulator written in Silverlight.

(hide this)

Threading Considerations for Binding and Change Notification in Silverlight 5

Pete Brown - 10 January 2012

A reader of my Silverlight 5 book recently reached out to me about threading and why I create some objects on the UI thread in the examples. We discussed some of the reasons, but I felt this would be a good topic to share with everyone. In fact, this is one area where it would have been fun to go into great detail in my book, but there simply wasn't the space. Threading and cross-thread exceptions can be a bit of a mystery to new Silverlight and WPF developers.

Background

The user interface in Silverlight runs on a thread commonly known as the UI Thread. Any code you create in the code-behind, and any code it calls all the way down the chain, unless it explicitly creates another thread, runs on this same UI thread. It's not at all uncommon to see Silverlight and WPF applications which never explicitly create a second thread, but do make calls to other services which create background threads for processing.

There are many other examples, but networking is one place where the Silverlight .NET Framework explicitly creates (or uses) different threads. Not all calls return on the UI thread.

Threads other than the UI thread are not allowed to access or manipulate UI objects. If they attempt to do so, the runtime throws an Invalid Cross-Thread Access exception. It looks like this:

image

But wait! I wasn't accessing any UI objects from my code. What gives?

It's not always obvious that you're interacting with UI objects on the UI thread, though. Here's the stack trace from this particular exception:

{System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. --->
System.UnauthorizedAccessException: Invalid cross-thread access.
at MS.Internal.XcpImports.CheckThread()
at MS.Internal.XcpImports.GetValue(IManagedPeerBase managedPeer, DependencyProperty property)
at System.Windows.DependencyObject.GetOldValue(DependencyProperty property, EffectiveValueEntry& oldEntry)
at System.Windows.DependencyObject.UpdateEffectiveValue(DependencyProperty property, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, ValueOperation operation)
at System.Windows.DependencyObject.RefreshExpression(DependencyProperty dp)
at System.Windows.Data.BindingExpression.SendDataToTarget()
at System.Windows.Data.BindingExpression.SourcePropertyChanged(PropertyPathListener sender, PropertyPathChangedEventArgs args)
at System.Windows.PropertyPathListener.ReconnectPath()
at System.Windows.Data.Debugging.BindingBreakPoint.<>c__DisplayClass4.<BreakOnSharedType>b__3()
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Delegate.DynamicInvokeImpl(Object[] args)
at System.Delegate.DynamicInvoke(Object[] args)
at MainPagexaml.BindingOperation(Object BindingState, Int32 , Action )}

This stack trace was generated by trying to raise a PropertyChangedNotification when I manipulated a model object from a background thread. So, it was obvious that I was working with an object on the background thread, but it wasn't obvious that I'd get a cross-thread exception (well it was in this case, as I contrived the example). If you consider a larger application where you have division of ownership for different pieces, a client-side developer may simply work with your viewmodel, but not realize you're farming some work out to another thread.

I wrote a blog post back in 2010 ( Essential Silverlight and WPF Skills: The UI Thread, Dispatchers, Background Workers and Async Network Programming) explaining some of the ways to work with threads and dispatching. I didn't have SynchronizationContext in there at the time, but it's something I tend to use a lot these days.

Let's take a look at a few of the common scenarios and how it works with threading.

Common Scenarios

All of these scenarios make use of a simple Customer class with a single property:

namespace SilverlightThreadingExample.Model
{
public class Customer : Observable
{
private string _firstName;
public string FirstName
{
get { return _firstName; }
set { _firstName = value; NotifyPropertyChanged("FirstName"); }
}
}
}

The customer is observable that is, it notifies any listeners when properties change. While not necessary, I encapsulated the observable code in this base class. You could, instead, put the implementation in a partial class if you wanted to make sure your model object's signature from your ORM or whatever remains the same as it was on the server.

using System.ComponentModel;

namespace SilverlightThreadingExample
{
public class Observable : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}

This is actually a pretty typical approach to handling INotifyPropertyChanged. There are even more robust versions out there which use lambdas and reflection to help avoid passing in strings, but they ultimately come down to raising the PropertyChanged event. Many of them also fail to work properly in cross-thread situations.

I expose the Customer class and a collection of customers from a ViewModel class.

namespace SilverlightThreadingExample.ViewModel
{
public class CustomerEntryViewModel : Observable
{
private Customer _currentCustomer;
public Customer CurrentCustomer
{
get { return _currentCustomer; }
set { _currentCustomer = value; NotifyPropertyChanged("CurrentCustomer"); }
}

private ObservableCollection<Customer> _customers = new ObservableCollection<Customer>();
public ObservableCollection<Customer> Customers
{
get { return _customers; }
}

public void LoadCustomersOnSameThread()
{
LoadDummyData();
}

private void LoadDummyData()
{
_customers.Add(new Customer() { FirstName = "Pete" });
_customers.Add(new Customer() { FirstName = "Jon" });
_customers.Add(new Customer() { FirstName = "Tim" });
_customers.Add(new Customer() { FirstName = "Scott" });
_customers.Add(new Customer() { FirstName = "Andy" });
_customers.Add(new Customer() { FirstName = "Blaine" });
_customers.Add(new Customer() { FirstName = "Jesse" });
_customers.Add(new Customer() { FirstName = "Rey" });

_currentCustomer = _customers[0];
}

}
}

Finally, the UI is bound to those classes. The DataContext for the UI (which will be set in code-behind) is the ViewModel.

<UserControl x:Class="SilverlightThreadingExample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="600">

<Grid x:Name="LayoutRoot" Background="White">
<Grid Width="500">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="250" />
</Grid.ColumnDefinitions>

<ListBox x:Name="CustomerList"
Grid.Column="0" Margin="10"
ItemsSource="{Binding Customers}"
SelectedItem="{Binding CurrentCustomer, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding FirstName}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

<StackPanel Grid.Column="1">
<TextBox x:Name="FirstNameField" Margin="10"
DataContext="{Binding CurrentCustomer}"
Text="{Binding FirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

<Button x:Name="AddCustomer"
Content="Add Customer from UI Thread"
Height="30" Margin="5"
Click="AddCustomer_Click" />
<Button x:Name="AddCustomerSecond"
Content="Add Customer from Second Thread"
Height="30" Margin="5"
Click="AddCustomerSecond_Click" />
<Button x:Name="ChangeNameFromSecondThread"
Content="Change Name from Second Thread"
Height="30" Margin="5"
Click="ChangeNameFromSecondThread_Click" />
</StackPanel>

</Grid>

</Grid>
</UserControl>

The code-behind looks like this

using System.Windows;
using System.Windows.Controls;
using SilverlightThreadingExample.ViewModel;
using System.Threading;
using SilverlightThreadingExample.Model;

namespace SilverlightThreadingExample
{
public partial class MainPage : UserControl
{
CustomerEntryViewModel _vm;

public MainPage()
{
InitializeComponent();

CreateViewModelOnUIThread();
}


private void CreateViewModelOnUIThread()
{
_vm = new CustomerEntryViewModel();

_vm.LoadCustomersOnSameThread();

DataContext = _vm;
}


private void AddCustomer_Click(object sender, RoutedEventArgs e)
{
}


private void AddCustomerSecond_Click(object sender, RoutedEventArgs e)
{
}


private void ChangeNameFromSecondThread_Click(object sender, RoutedEventArgs e)
{
}


}
}

The methods are named to keep the context clear in this example. I wouldn't expect you to name your VM instantiation/locator method "CreateViewModelOnUIThread", for example.

Now let's look at those scenarios.

Changing a property value from a background thread

Often in an application, you have a class which is used in UI binding (an entity/model object) but still need to modify a property from code. Sometimes, you need to do that from a background thread. For example, you make a network call to get an updated price for an item. You will get a cross-thread access error when the class raises change notification events from that property setter. If the class is truly POCO (Plan Old CLR Object) and doesn't do any change notification or other event raising, you'll be fine. If, however, change notification is involved, you'll get the cross-thread exception.

image

Assuming the same Customer and Observable classes defined above, and the same XAML UI, the following code in the code-behind will throw that exception.

private void ChangeNameFromSecondThread_Click(object sender, RoutedEventArgs e)
{
Thread t = new Thread((o) =>
{
_vm.CurrentCustomer.FirstName = "UpdatedFromSecondThread";
});

t.Start();
}

The exception doesn't happen when you set the property value; that's perfectly acceptable. It happens here, at the highlighted line:

protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}

So, what are the options for working around this? Let's consider two common approaches.

Approach 1

The first approach is to do the whole property change from the UI thread. To do this, simply wrap the property set code with a call to the dispatcher. You can use either the Dispatcher object, or if you keep a copy of the SynchronizationContext around, use that.

image

Here's some example code which implements this. The code looks a bit silly because I'm forcing a background thread. However, pretend that the background thread is a given and you need to work from it (again, the callback from a network call or something.)

private void ChangeNameFromSecondThread_Click(object sender, RoutedEventArgs e)
{
Thread t = new Thread((o) =>
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
_vm.CurrentCustomer.FirstName = "UpdatedFromSecondThread";
});
});

t.Start();
}

This approach works well, but requires the calling code to handle all the dispatching. If you have a number of properties to change in different bits of code, it gets a bit cumbersome. Let's look at another approach.

Approach 2

The real problem is the property change notification, so the the second approach is to dispatch just the change notification to the UI thread.

image

You can put this code into the Observable base class in order to avoid repeating it throughout all your classes.

// Code-behind
// ----------------------------------------------


// this version throws an exception if the Observable base class isn't doing thread checking
private void ChangeNameFromSecondThread_Click(object sender, RoutedEventArgs e)
{
Thread t = new Thread((o) =>
{
_vm.CurrentCustomer.FirstName = "UpdatedFromSecondThread";
});

t.Start();
}


// Observable
// ----------------------------------------------


using System.ComponentModel;
using System.Windows;

namespace SilverlightThreadingExample
{
public class Observable : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
if (Deployment.Current.Dispatcher.CheckAccess())
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
else
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
});
}
}
}
}
}

Note how I first check to see if we have access to the UI thread using the CheckAccess call. If we do, there's no reason to incur the overhead and delay of a dispatcher call. However, if we are running on the background thread, then the call is dispatched to the UI thread. In either case, we avoid the errors cause by cross-thread property change notification.

Next up: Collections

Populating an ObservableCollection from a networking return call

A more robust Observable base class like this won't help with collection change notification (WPF 4.5 has a great solution for that using BindingOperations.EnableCollectionSynchronization, but unfortunately Silverlight does not).

Most applications make networking calls to get information from some resource on an intranet or out on the web. In Silverlight (and WPF), it's common practice to populate an ObservableCollection with the results from those calls. The ObservableCollection class is nice because it implements INotifyCollectionChanged and raises an event whenever items are added to or deleted from the collection, or when the collection is cleared. It's this notification that enables the various items controls and grids in the UI to stay in sync with the items in the collection.

image

This version is very similar to what we saw with individual properties earlier. That's because, it's really the same problem: we're trying to notify the binding system across threads.

private void AddCustomerSecond_Click(object sender, RoutedEventArgs e)
{
Thread t = new Thread((o) =>
{
var cust = new Customer() { FirstName = "AddedFromSecondThread" };
_vm.Customers.Add(cust);
});

t.Start();
}

Note that the problem exists regardless of where you actually create the customer. For example, this code will also fail:

private void AddCustomerSecond_Click(object sender, RoutedEventArgs e)
{
var cust = new Customer() { FirstName = "AddedFromSecondThread" };

Thread t = new Thread((o) =>
{
_vm.Customers.Add(cust);
});

t.Start();
}

The reason is, again, it's not the object access that is causing the cross-thread exception, it's the collection changed notification that's full of hate here.

So, how do you get around this? Unless you want to create your own ObservableCollection type class for Silverlight, you'll need to dispatch all collection add calls. Luckily, you'll typically have fewer of these scattered throughout the application, so it's not quite so onerous.

image

The code to implement this is just another easy call to the dispatcher (or SynchronizationContext, if you prefer).

private void AddCustomerSecond_Click(object sender, RoutedEventArgs e)
{
// you can create customer on any thread
var cust = new Customer() { FirstName = "AddedFromSecondThread" };

Thread t = new Thread((o) =>
{

// dispatch to UI thread to add it to the collection. You can't
// access the observable collection x-thread
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
_vm.Customers.Add(cust);
});
});

t.Start();
}

If you're going to run from an unknown state, be sure to call CheckAccess to see if you really need to do the dispatching. In this case, I know I'm always going to be on a background thread, so I don't bother.

Summary

The intent here was to show a few of the common threading pitfalls in Silverlight (and WPF) applications, specifically in the context of change notification. In most code, it's easy to tell when you're accessing objects cross-thread, but change notification is a somewhat behind the scenes operation, so it's not always obvious.

For property change notification, the solutions were:

  • Dispatch the entire property change operation to the UI thread
  • Update the NotifyPropertyChanged code to check to see which thread it's running on, and then dispatch the event as appropriate

Either way works, but I prefer the update to the NotifyPropertyChanged method.

For collection change notifications in Silverlight, the solutions are:

  • Create (or find) an implementation of ObservableCollection which does the cross-thread checking. The reason this isn't built-in is change notification happens often, and dispatching each and every change notification can be a real performance drain. That's also why WPF has a separate and optimized solution. You'd need to enable batching to avoid the overhead of hundreds of dispatch calls.
  • Dispatch the entire collection update when you're running on a background thread.

In contrast to the property change notifications, for collection change, I prefer to dispatch the entire call. If you're adding 1 object or 100, you'll still get only one dispatch call, so performance is better.

The Task Parallel Library in WPF, and the subset of it in Silverlight also offer some alternative approaches to handling cross-thread work. Similarly, the async and await keywords in .NET 4.5 and Windows 8 XAML can also come into play. More on those in the future.

             

Source Code and Related Media

Download /media/82326/silverlightthreadingexample.zip
posted by Pete Brown on Tuesday, January 10, 2012
filed under:              

12 comments for “Threading Considerations for Binding and Change Notification in Silverlight 5”

  1. Einar G.says:
    One point.
    If you change collection on diffrent thread then notify on UI thread be sure that nothing on UI thread starts reading that collection. Lets say it is datagrid Grid will still think there is 100 items even tough you just removed almost all of them. Fun exceptions come out of that.

    regards
    EG
  2. Paulussays:
    Hi Pete,

    Excellent article! Hope more examples will become available.

    For the sake of clarity, barring any mistake on my part,
    - WPF 4.0 (and earlier) allows cross-thread data binding: the CheckAccess() is not necessary if the NotifyPropertyChanged method
    - WPF 4.0 (and earlier) does not support cross-thread collection mutation. The exception is: “This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.”
    - WPF 4.5 (final release) might support cross-thread collection mutation, from what I heard. However, the performance penalty and possible limitations due to inter-thread collection locking are unknown to me. It is also unclear whether performance will be OS-dependent (W7 versus W8), if WPF 4.5 is released on W7 that is.
    Kind regards, Paulus
  3. Spammesays:
    I would prefer to leave my data classes without references to the UI namespace (SoC), so I can reuse them else where, plain old C# code.
    I would expect that the binding will do it for me, as a bridge from my data objects and the UI, it should also handle such cases and be "thread safe".
    Perhaps a "thread safe" binding can be implemented as a custom markup extension ... Nicer would be to override the standard xaml parser and instantiate a "thread safe" binding for the binding. Better would it be if microsoft had already though to it and implemented in the binding object.

  4. Mark Lindellsays:
    I have always known that I would have to marshal calls to the UI thread make updates but yesterday was the first time I had to actually do it. I updated properties on my ViewModel from a background thread and didn't use the Dispatcher. I did not get an exception and I was left scratching my head. I found the following blog post which lead me to believe that changes using bindings were already using the Dispatcher.

    http://blog.lab49.com/archives/1166

    Is that article correct and my thinking correct that it works fine through bindings?
  5. Vitaliysays:
    Just short comment on this code:
    Deployment.Current.Dispatcher.BeginInvoke(() =>
    {
    _vm.Customers.Add(cust);
    });

    I think you should cast lambda to Delegate, something like this:
    Deployment.Current.Dispatcher.BeginInvoke((Action)(() =>
    {
    _vm.Customers.Add(cust);
    }));

    Other wise code can not be compiled with error: Error
    Cannot convert lambda expression to type 'System.Windows.Threading.DispatcherPriority' because it is not a delegate type
  6. Petesays:
    @Vitaliy

    What version are you compiling with? That compiles as written in Silverlight 5. No cast needed.

    In fact, I can't recall ever having to cast that to Action. Something else going on in your code?

    Pete
  7. Rameshsays:
    Hi Pete,

    Thank you very much for your explanation.
    Can you just elaborate on the below statement

    In Summary above,

    That's also why WPF has a separate and optimized solution.

    or you can also give me link where I can learn the solution for Wpf
    I am looking for a solution in WPF, I am using .Net4.0

    Regards,
    Ramesh M
  8. Anthonysays:
    This approach will surely take care of the cross-thread binding issue but does nothing to resolve the thread-safety issues. Try this collection which takes care of this problem as well as other multi-threaded problems that will inevitably crop up with other approaches : http://www.codeproject.com/Articles/64936/Multithreaded-ObservableImmutableCollection

Comment on this Post

Remember me