C# 基于BlockingCollection更改更新表单

C# 基于BlockingCollection更改更新表单,c#,multithreading,C#,Multithreading,我有一个多线程应用程序,其中每个线程都能够通过使用包含guiUpdateObjects的共享(且线程安全)BlockingCollection来记录挂起的GUI更新 每个guiUpdateObject都包含要更新的控件和要显示的内容的信息。我想让我的表单使用该BlockingCollection上存在的任何项,并相应地更新各种控件 在这个应用程序的Java版本中,这个设置对我来说很好,在生成线程和执行初始化任务之后,主线程在一个定时循环中检查项目 我想我也可以在C#中使用计时器事件来完成同样的操

我有一个多线程应用程序,其中每个线程都能够通过使用包含
guiUpdateObjects
的共享(且线程安全)BlockingCollection来记录挂起的GUI更新

每个
guiUpdateObject
都包含要更新的控件和要显示的内容的信息。我想让我的表单使用该
BlockingCollection
上存在的任何项,并相应地更新各种控件

在这个应用程序的Java版本中,这个设置对我来说很好,在生成线程和执行初始化任务之后,主线程在一个定时循环中检查项目

我想我也可以在C#中使用计时器事件来完成同样的操作,但是考虑到Windows窗体中所有的本机事件处理,我想知道是否有更好的方法。也许,有一个定制的活动?如果您对我目前的方法有任何批评和/或对如何最好地在C#中实现这一点提出建议,我们将不胜感激

根据Hans的建议更新:

在阅读了Control.BeginInvoke()之后,我了解到这将允许我将消息传递到应用程序消息队列。这类似于我对BlockingCollection的使用,因为它是线程安全的,可以在不等待消息处理的情况下立即返回

然而,使用BeginInvoke需要使用委托,在阅读了它们之后,我仍然对正确的实现有点困惑。我是在Form类中声明委托,还是在将生成gui更新内容的worker类中声明委托?如果我在Form类中声明,除非我引用Form对象,否则worker类将看不到该方法。或者,如果我在worker类中声明,Form类将如何在委托方法和实际方法之间建立关联?这里有一些代码强调了我的问题:

public partial class GUI : Form
{

    public GUI()
    {
        InitializeComponent();

        Thread workerThread = new Thread(new ThreadStart(new Worker().DoWork));
        workerThread.Start();
    }

    private delegate void AppendSysLogDelegate(string logEntry);
    private void AppendSysLog(string logEntry)
    {
        if (this.InvokeRequired)
        {
            this.BeginInvoke(new AppendSysLogDelegate(AppendSysLog), new object[] { logEntry });
            return;
        }
        systemLogger.AppendText(logEntry);
    }
}

public class Worker
{
    public void DoWork()
    {
    //what goes here to call AppendSysLog("Test log entry");
    }
}

检查此问题并记下优秀答案:

现在您已经装备了一个等价的
blockingCollection.TakeAsync()
,您可以
在UI线程上等待它的结果,例如:

async void btnTest_Click(object s, EventArgs e)
{
   // don't forget to add exception handling
   while(true)
   {
        var result = await blockingCollection.TakeAsync();
        this.textBox.AppendText(result.ToString());
   }
}

在我看来,没有“C#form”这样的东西。你发明了Control.BeginInvoke()维护的调用队列。是的,它后面有一个事件,确保这个队列被清空,它是内部队列。只需使用BeginInvoke()。在任何关于Winforms编程的介绍性文章或书籍中阅读更多有关它的内容。@HansPassant谢谢-这里有一个关于BeginInvoke的非常好的教程:。我更新了我的原始问题,对BeginInvoke和代表进行了一些跟进。此外,如果将AppendSysLog方法设置为静态,这样我就不必将GUI对象传递给使用它的每个类以使其可见,这会有什么影响吗?考虑委托最简单的方法就是想象它引用方法签名。当您将委托视为参数时,可以在其所在位置使用lambda(匿名方法),或者仅使用与委托的方法签名匹配的任何其他命名方法。