我偶然发现了专业库中的一些代码,不确定这是否是处理跨线程事件调用的干净方法。

下面的代码在一个表单应用程序中。线程调用是从一个本身启动一个新线程并接收消息的类进行的:

private void Library_StatusChanged(object sender, AbstractTestCase.StatusChangedEventArgs e)
{
    if (this.InvokeRequired)
    {
        this.lblProgress.Invoke((MethodInvoker)delegate ()
        {
            lblProgress.Text = "Current state: " + e.Step;
            lblProgress.Refresh();
        }
        );

        this.pbProgess.Invoke((MethodInvoker)delegate ()
        {
            pbProgess.Value = e.Percentage;
            pbProgess.Refresh();
        });

        this.lstStatus.Invoke((MethodInvoker)delegate ()
        {
            lstStatus.Items.Add("    " + e.Step);
            lstStatus.Refresh();

        });

        this.Invoke((MethodInvoker)delegate ()
        {
            this.Refresh();
        });
    }
    else
    {
        lblProgress.Text = "Current state:" + e.Step;
        lblProgress.Refresh();

        pbProgess.Value = e.Percentage;
        pbProgess.Refresh();

        lstStatus.Items.Add("    " + e.Step);
        lstStatus.Refresh();

        this.Refresh();
    }

    Application.DoEvents();
}

这是“最先进的”吗?在我看来这有点乱?!

最佳答案

最先进的技术是使用 await 。如果这里不可能,至少将代码简化为单个 Invoke 调用。不需要在每个控件上调用,只需在 UI 线程上的任何地方调用。
InvokeRequired 检查不是必需的,因为您应该知道在哪个线程上引发事件。

在任何情况下,复制诸如 "Current state: " + e.Step 之类的逻辑确实是一个坏主意,无论如何我都会在代码审查中失败。
Application.DoEvents 的存在是一个非常糟糕的迹象。可能是一个误解,因为它只在 UI 线程上调用才有意义,但是为什么 Invoke 已经在 UI 线程上?!看起来很矛盾。
lstStatus.Refresh(); 也是一种误解,可能是迷信。控件自动刷新(如果您允许事件处理)。

关于c# - 线程安全事件 - 这是 "clean"方式吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34069174/

10-12 12:44
查看更多