Why does C# make you put in a dispatcher for a different thread to update the UI?


Dispatcher.Invoke(() =
    lblerrorName.Content = "";

It always gives the 'running on different thread' exception, but if it knows I want to change a label which is on the UI thread, why isn't it automatic and behind the scenes.

It adds complexity and extra code for no apparent reason, can someone explain why it's like this?


why isn't it automatic and behind the scenes.

This would work as long as there is only one action for one property of one component is involved, but as soon as there are more actions, maybe actions which are dependent on each other, one would have a high risk of running into race conditions. The explicit "Invoke" mechanics works like a transactional bracket and lets the programmer group multiple statements in an atomic fashion together.

For example, if WPF would invoke control actions "behind the scenes", each control property access would be a deferred one on its own. That would lead to very strange effects for code like this:

 lblerrorName.Content = "ABC"; // this assignment is deferred 
 // ...
 lblerrorName.Content = lblerrorName.Content + "DEF"; // "ABCDEF"? Maybe not.

Such code could produce different behaviour when run in the UI thread, outside the UI thread, or in a debugger in a step-by-step manner.

However, explicit invoking allows the programmer to bundle different component manipulation statements intentionally together:

Dispatcher.Invoke(() =
    lblerrorName.Content = "ABC";
    lblerrorName.Content = lblerrorName.Content + "DEF";  // "ABCDEF"

So this is way less error-prone than an automatism.

As a secondary point, in scenarios where one has to manipulate a multiple control data, maybe in a loop, automatic invoking could als have a notable performance impact.

|improve this answer|||||
  • That is an odd example. Why wouldn't one simply log the original value? – Robert Harvey May 29 '19 at 14:40
  • @RobertHarvey: ok, better now? The point is, setting a property and reading the value again might not show expected result. – Doc Brown May 29 '19 at 14:50
  • Oh, I get the example. But unless I'm doing something specifically on the UI (so by definition I'm already on the UI thread), I don't generally refer to UI controls like this; I refer to the original data. – Robert Harvey May 29 '19 at 14:52
  • @RobertHarvey: yes, my example is a little bit contrived - for the sake of simplicity. Feel free to suggest a better one which is still simple but not so artificial. – Doc Brown May 30 '19 at 7:03
  • While this is a fantastic point if the invocations were deferred, I don't see that there is any reason why the operation shouldn't be run synchronously on the other thread (as is the case with most Invoke methods, as opposed to BeginInvoke). Performance would presumably be nightmarish in the multiple-updates case, but this seems to be what the OP was suggesting (by my reading, at least, though it's not entirely clear). – VisualMelon May 30 '19 at 9:41

If your program wants to update the UI from a non-UI thread, the application framework has two choices:

  • block the non-UI thread until the UI thread is waiting for events, then lock out the UI thread until the non-UI thread has done its update.
  • let the non-UI thread specify the update as a deferred action, i.e. some code that can be executed by the UI thread at a convenient time.

The latter option is more versatile since it allows the non-UI thread to continue and possibly specify more updates which can then be executed in sequence. It also avoids possible deadlock issues because neither thread needs to wait on the other while potentially holding a resource lock.

I presume these are the main reasons why the C# framework is using the Dispatcher approach.

|improve this answer|||||

For thread safety: the threading apartment used by WPF controls is STA, which only allows the thread which created the components to modify them. This is done to increase thread safety on objects that are not inheritly thread safe.

Changing something on a background thread might indicate a threading error on behalf of the programmer, hence the exception and forcing you to marshal back to the original STA thread. Having automatic dispatch would practically defeat this purpose

|improve this answer|||||

You are assuming the C# compiler and IDE are or should be aware of what you are doing and to what purpose. They don't, C# is a third generation programming language. OK, you get a template because you told the IDE you are doing a WPF application or a Windows Forms application, that will give you a head start and some guidance. But knowing which operations are thread safe and which are not and how to deal with these in specific scenarios requires way too much intelligence. The C# compiler and IDE do not read documentation. And if they did, you would probably not agree with the way they handled things and with the choices they made anyway. There is little as annoying as software that makes decisions for you rather than just obeying your commands.

|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.