C# 在其他线程中触发事件后更新事件处理程序中UI的最佳方法

C# 在其他线程中触发事件后更新事件处理程序中UI的最佳方法,c#,wpf,multithreading,cross-thread,C#,Wpf,Multithreading,Cross Thread,我的项目需要通过事件更新一些UI元素,其中一些事件在异步或后台线程中触发。所以我需要在事件处理程序中添加一些线程安全代码 但我发现在这个项目中有很多相同的情况。这些分散的线程安全代码使得整个项目代码非常难看,我希望有办法改进它 下面是其他线程中火灾事件的示例代码: public static class MyAsyncClass { public static event Action MyEvent; public static void AsyncCallEvent()

我的项目需要通过事件更新一些UI元素,其中一些事件在异步或后台线程中触发。所以我需要在事件处理程序中添加一些线程安全代码

但我发现在这个项目中有很多相同的情况。这些分散的线程安全代码使得整个项目代码非常难看,我希望有办法改进它

下面是其他线程中火灾事件的示例代码:

public static class MyAsyncClass
{
    public static event Action MyEvent;
    public static void AsyncCallEvent()
    {
        //...
        Task.Run(() => {
            while(runningFlag)
            {
                //...
                if(flag)
                    MyEvent?.Invoke();
            }
        });
    }
}
public class MyWindow : Window
{
    //...
    private void OtherMethod()
    {
        UpdateText();
    }
    private void Init()
    {
        MyAsyncClass.MyEvent += UpdateText;
    }
    private void UpdateText()
    {
        //Do update
    }
    //...
}
private void Init()
{
    MyAsyncClass.MyEvent += () => Dispatcher.Invoke(UpdateText);
}

private void UpdateText()
{
    MyTextBox.Text = "NewText";
}
以下是updateText的两种代码:

//Clear, but not cross-thread safety
//will fail in cross-thread event invoking
private void UpdateText()
{
    MyTextBox.Text = "NewText";
}
当然,第二个代码肯定更好,但如果将其添加到所有可能以异步方式调用的事件处理程序中,代码将变得令人不快


有更干净的解决方案吗?

那么,您可以在调度程序线程上调用
UpdateText()
本身:

public static class MyAsyncClass
{
    public static event Action MyEvent;
    public static void AsyncCallEvent()
    {
        //...
        Task.Run(() => {
            while(runningFlag)
            {
                //...
                if(flag)
                    MyEvent?.Invoke();
            }
        });
    }
}
public class MyWindow : Window
{
    //...
    private void OtherMethod()
    {
        UpdateText();
    }
    private void Init()
    {
        MyAsyncClass.MyEvent += UpdateText;
    }
    private void UpdateText()
    {
        //Do update
    }
    //...
}
private void Init()
{
    MyAsyncClass.MyEvent += () => Dispatcher.Invoke(UpdateText);
}

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

但是,代码真正难看的地方在于,您正在使用
Task.Run
MyAsyncClass
中的另一个线程上显式执行事件处理程序。您应该在引发事件的同一线程上调用事件处理程序。然后由事件的订阅者选择是否将事件处理程序中的代码卸载到另一个线程。

如果您的代码正常工作,我想这是一个离题的问题,您应该在stackexchange site?@vasily.sib上问这个问题。这个问题可能符合的描述,因此我不会在CodeReview中问它。这里没有异步。您刚刚启动了一个后台线程。不要在后台线程上引发与UI相关的事件。是否可以通过添加属性等方式修改
MyAsyncClass
?我猜OP正在使用
Task.Run
调用事件,以避免被顽皮的事件处理程序阻止。它与使用MyEvent?异步调用它没有太大区别。BeginInvoke(…。事实上,这是一个轮询任务,我已经修改了我的代码。这个解决方案看起来不错,但我决定在问题重新打开后再等待一些新的答案。