I was tasked with a small WinForms application a while back which contained a long running calculation. The user would initiate the calculation by pressing a button and when the calculation was complete, the result would then be displayed in a textbox. I also wanted to build the application using different layers so that each layer could vary independently.
I decided to implement this application using the Model-View-Presenter (MVP) pattern. I would set the long running process to run on a different thread (of course) and when the calculation was complete, I would have the presenter update the view. Sounds easy, right? Let’s see.
I used basic data binding to bind a textbox on the view which would display the results:
txtTotal.DataBindings.Add("Text", this, "Total");
The Windows Form itself is the view (implements the
IView interface), so this is actually a self binding.
Now here's the issue. If the ‘
Total’ variable was updated on the UI thread, the data binding worked fine and the result was displayed in the textbox. However because I wanted the long running task to be executed on a different thread, when I updated the view from the presenter in a different thread, I received the following error:
'Cross-thread operation not valid: Control 'txtTotal' accessed from a thread other than the thread it was created on'
Every developer has seen this error before and hates it with every 'fiber' of his/her being. No pun intended. Data binding in .NET does not allow updating of data from a different thread. So how can we solve this?
There are quite a few solutions to this issue like the
BackgroundWorker component. However the solution I chose involved the
SynchronizationContext object (which a
BackgroundWorker uses behind the scenes. Each thread has
SynchronizationContext associated with it. You can use this context to execute code using a specified thread either using the
Post (asynchronous) or
Send (synchronous) methods.
To get a reference to the
SynchronizationContext, you can use the following code:
I simply use the view’s
SynchronizationContext object whenever I update any databinded property on the view from the presenter. Here is my code for the presenter:
internal class Presenter : IPresenter
public Presenter(IView view)
this.View = view;
this.Context = this.View.Context;
private IView View
private SynchronizationContext Context
private void View_OnLongRunningCalculationRequested(object sender, EventArgs e)
Thread thread = new Thread(RunLongRunningProcess);
private void RunLongRunningProcess()
if (Context != null)
decimal data = 1000 + 10;
View.Total = data;
Notice I update the
Total property of the view using its own
SynchronizationContext. That means the actual delegate gets called from the UI thread. And now, the view's binding to the '
Total' property works as expected.
Have fun and send any comments my way.
- 15th March, 2010: Initial post