-1

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?

  • 3
    If your code works, I guess this is offtopic for SO and you should ask this question on [another](https://codereview.stackexchange.com/) stackexchange site? – vasily.sib Jun 01 '20 at 04:13
  • 2
    @vasily.sib This question may fit the description of https://codereview.stackexchange.com/help/dont-ask So I won't ask it in CodeReview – Mr. Squirrel.Downy Jun 01 '20 at 06:03
  • There is nothing async here. You have just started a background thread. Simply don't raise UI related events on a background thread. – BionicCode Jun 01 '20 at 14:21
  • Is it an option to modify the `MyAsyncClass`, for example by adding a [`SynchronizingObject`](https://learn.microsoft.com/en-us/dotnet/api/system.timers.timer.synchronizingobject) property? – Theodor Zoulias Jun 01 '20 at 15:16

1 Answers1

2

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.

mm8
  • 163,881
  • 10
  • 57
  • 88
  • I guess that the OP is using `Task.Run` to invoke the event, in order to avoid being blocked by naughty handlers of the event. It's not that much different than invoking it asynchronously with `MyEvent?.BeginInvoke(...`. – Theodor Zoulias Jun 01 '20 at 15:10
  • In fact, this is a polling task, I have modified my code. This solution looks good, but I decided to wait some more new answer after the problem is reopened. – Mr. Squirrel.Downy Jun 02 '20 at 01:45