How should I simplify the code for updating controls on the UI thread by Dispatcher

1.4k Views Asked by At

My codes need to update some UI element by triggerd event, and some of event is trigged in async or background thread, not in STA thread. So I need use Dispatcher.Invoke in event handler.

But there is so many same situation need to apply. These scattered thread-safe code makes the project codes look not elegant at all, I hope there is a way can improve it.

Here is the sample code of fire event in other thread(not real code):

//heres code just to simulate triggering events on non-STA threads
public static class MyAsyncClass
{
    public static event Action MyEvent;
    public static void AsyncCallEvent()
    {
        Task.Run(() => MyEvent?.Invoke());
    }
}
public class MyWindow : Window
{
    //...
    private void OtherMethod()
    {
        //safe
        UpdateText1();
        //throw exception
        AsyncCallEvent();
    }
    private void Init()
    {
        MyAsyncClass.MyEvent += UpdateText1;
    }
    private void UpdateText1()
    {
        //will throw exception in cross-thread invoking
        MyTextBox1.Text = "NewText";
        //safe but noisy
        Dispatcher.Invoke(() => MyTextBox1.Text = "NewText");
    }
    //some else method may will be invoke by cross-thread
    private void UpdateText2(){}...
    private void UpdateText3(){}...
    private void UpdateText4(){}...
    private void UpdateText5(){}...
    //...
}

Sure, use Dispatcher.Invoke is definitely better, but if add it to all event handler that may potentially be called in async, the code will become make people unpleasant.

Is there a cleaner solution?

1

There are 1 best solutions below

2
On BEST ANSWER

Well, you could invoke UpdateText() itself on the dispatcher thread:

private void Init()
{
    MyAsyncClass.MyEvent += () => Dispatcher.Invoke(UpdateText);
}

private void UpdateText()
{
    MyTextBox.Text = "NewText";
}

But what is truly ugly about your code is that you are using Task.Run to explicitly execute the event handler on another thread in MyAsyncClass. You should invoke the event handler on the same thread where the event was raised. It's then up to the subscriber of the event to choose whether to offload the code in the event handler to another thread.