根据BlockingCollection更改更新表单

时间:2014-01-18 17:51:46

标签: c# multithreading

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

每个guiUpdateObject包含有关要更新的控件和要显示的内容的信息。我希望我的表单使用BlockingCollection上存在的任何项目并相应地更新各种控件。

此设置以前在此应用程序的Java版本中运行良好,在生成线程和执行初始化任务之后,主线程在定时循环中检查项目。

我想我可以在C#中使用计时器事件做同样的事情但是在Windows窗体中给出了所有本机事件处理,我想知道是否有更好的方法。也许,有一个自定义事件?非常感谢对我当前的方法提出任何批评和/或如何在C#中最好地实现这一点的建议。

根据汉斯的建议更新:

在阅读Control.BeginInvoke()之后,我明白这将允许我将PostMessage发送到应用程序消息队列。这类似于我对BlockingCollection的使用,因为它是线程安全的,并且无需等待处理消息即可立即返回。

但是,使用BeginInvoke需要使用委托,在阅读完它们之后,我仍然对正确的实现感到困惑。我是在Form类中还是在'worker'类中声明将为gui更新生成内容的委托?如果我在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");
    }
}

1 个答案:

答案 0 :(得分:0)

检查这个问题,并记下优秀的答案:

Is there anything like asynchronous BlockingCollection<T>?

现在你已经使用等效的blockingCollection.TakeAsync(),你可以在UI线程上await结果,例如:

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());
   }
}