WinForms相当于Objective-C中的performSelectorOnMainThread

时间:2010-03-17 14:10:33

标签: c# winforms multithreading

之前我没有做太多多线程,现在发现需要做一些后台工作并保持UI响应。我有以下代码。

data.ImportProgressChanged += new 
     DataAccess.ImportDelegate(data_ImportProgressChanged);

Thread importThread = new Thread(
       new ThreadStart(data.ImportPeopleFromFAD));
importThread.IsBackground = true;
importThread.Start();

void data_ImportProgressChanged(int progress)
{
    toolStripProgressBar.Value = progress;
}

//In my data object I have 
public void ImportPeopleFromFAD()
{
    ImportProgressChanged(someInt);
}

但是,由于在后台线程上进行ImportProgressChanged()调用,因此UI不会更新。在目标C中我知道你可以使用performSelectorOnMainThread并传递一个方法来使用主线程进行调用。从主线程调用ImportProgressChanged()的等效方法是什么?

3 个答案:

答案 0 :(得分:2)

(假设使用Windows窗体。)您可以使用Control.InvokeControl.BeginInvoke - 但可以更清洁的方式使用BackgroundWorker开始。

在WPF中,您使用Dispatcher代替Control.Invoke,顺便说一下。有关详细信息,请参阅此WPF threading model guide

编辑:我个人可能不会先打扰InvokeRequired - 我只需拨打InvokeBeginInvoke。如果你已经“开启”正确的线程,它将不会造成任何重大伤害。

对于进度条,BackgroundWorker绝对是前进的方向。

答案 1 :(得分:1)

而不是更新GUI,data_ImportProgressChanged应该在被调用时抛出异常更改进度条。

最短的更改是使用Control.InvokeRequired和.Invoke(),但Backgroundworker是专为此方案创建的。

如果你想在数据对象中解决它,你必须依赖于GUI,所以最好在处理程序中解决这个问题:

void data_ImportProgressChanged(int progress)
{
    if (toolStripProgressBar.InvokeRequired)
    {
        Action<int> a = new Action(data_ImportProgressChanged);
        toolStripProgressBar.Invoke(a, progress);
    }
    else
        toolStripProgressBar.Value = progress;
}

答案 2 :(得分:0)

你已经有了答案,但无论如何我都会添加我的解决方案:

void data_ImportProgressChanged(int progress)
{
    if (InvokeRequired)
    {
        BeginInvoke(new Action<int>(data_ImportProgressChanged),progress);
        return;
    }

    toolStripProgressBar.Value = progress;
}