2010-02-08 139 views
0

我有一个线程从一个网站收集URL列表并更新UI,因为它是这样做的。这工作正常。但是,我需要主线程来等待链接被收集。我试图加入,但是这会锁定用户界面。这是我的例子。正如你现在所看到的,foreach循环在线程运行的同时被调用。我希望foreach在线程运行后运行。线程和正在等待

任何想法?

/** This thread will add links to list<string> linkList **/ 
Thread linkListThread = new Thread(new ThreadStart(getLinkList)); 
linkListThread.Start(); 
foreach (String link in linkList) 
{ 
    txtOutput.Text += link; 
} 
+0

A面提示,你可以这样做'txtOutput.Text =的string.join( “”,linkList.ToArray() )',在记忆上更快更好。 – 2010-02-08 12:45:04

+0

如果您当前的线程只是产生另一个线程来完成这项工作,然后必须等待该线程完成,那么为什么要使用两个线程来完成此任务?为什么不直接调用直接完成工作的代码呢? – 2010-02-10 11:12:11

回答

1

移动需要的线程已经完成到事件处理程序BackgroundWorker.RunWorkerCompleted

更新后运行该代码:处理程序在右侧调用(调用的)线程 - 这样你就可以安全地更新UI。

请参阅上述msdn页面上的代码片段。

+1

不,RunWorkerCompleted代码由后台工作者自动在窗体的线程上下文中调用。 – 2010-02-08 12:57:03

+0

我调用的方法... getLinkList(),是否需要更改为private void getLinkList(Object sender,DoWorkEventArgs args)? 所以我可以调用bw.DoWork + = getLinkList; ? – 2010-02-08 13:00:54

+0

是的。但是,也可以双击设计器中的DoWork事件,并将getLinkList()中的代码复制到新创建的事件处理程序中。别忘了:永远不要在DoWork中处理异常!他们将传递给e.Error中的RunWorkerCompleted事件。 – 2010-02-08 13:03:09

6

您可以使用后台工作器。或者让线程方法在完成时在主上下文中调用方法,传递您收集的项目列表。

编辑
我想我应该详细说明我的第二种方法。

List<string> links = new List<string>(); 

然后,你将这个名单给线程,填补它:

你可以创建线程之前准备一张列表实例

Thread t = new Thread(new ParameterizedThreadStart(FillList)); 
t.Start(links); 

线程方法采用列表,填充它并调用一个显示UI中细节的方法:

private static void FillList(object state) 
{ 
    List<string> links = (List<string>)state; 

    // Fill data 

    this.Invoke((MethodInvoker)delegate() { HandleNewLinks(links); })); 
} 

HandleNewLinks方法效果正如人们所预料:

private void HandleNewLinks(List<string> links) 
{ 
    foreach (string link in links) 
     // Do something... 
} 
+0

+1 - 这就是我想说的,所以我删除了我的答案。尽管不要忘记你需要使处理线程安全。 – ChrisF 2010-02-08 12:47:54

+0

当然,但我假设在这个示例中,该线程只创建一次以解耦填充列表并显示结果。无论如何,我最喜欢的解决方案是后台工作人员...... – 2010-02-08 12:55:26

0

目前尚不清楚你想要什么:无论是应用程序等待(并且是反应迟钝),或应用程序不会等待并保持响应。在后一种情况下,您可能需要禁用一些控件/可能的操作,直到列表完成加载。

一个肮脏的解决方法是做一些自旋等待(Join与超时几毫秒,返回结果是否完成)与一些Application.DoEvents()调用。

+0

我希望应用程序保持响应状态。我需要创建2个线程并加入它们吗? IE浏览器。线程收集链接,并输出一个线程? 将加入等待,直到线程完全完成? – 2010-02-08 12:46:58

+0

UI线程将执行输出(您不应该从另一个线程访问WinForms控件),另一个线程完成工作(获取链接)。所以UI线程有一个'while(!workerThread.Join(20)){Application.DoEvents(); }'这将等待另一个线程完成,同时保持消息泵(从而UI)运行。 – Lucero 2010-02-08 13:28:17

0

要简单的办法是有你的工作线程回调到上完成的主要应用,你再继续完成线程,并在您的主UI计数这样做:

while(runningThreads != 0) 
{ 
    Application.DoEvents(); 
} 

,并有螺纹电话:

void OnThreadCompleted() 
{ 
    runningThreads--; 
} 

更好地使用BackgroundWorker而不是创建自己的线程,因为它具有所有的回调机制。

0

我们已经使用了后台工作类似的东西,和它的工作很好,有两个意见:

  1. 不要添加文字与+ =,因为它会经过几个减慢你的速度大大的文本框百行。改用AppendText。

  2. 如果您向接口添加大量信息并且有睡眠时间(处理过程中),线程可能会“睡着”。我们通过每200行删除文本框中的文本来修复它(结果写入文件,所以我们没有丢失任何东西)。

0

一种选择是简单地在主线程中使用Invoke

void YourMethod() 
{ 
    Thread linkListThread = new Thread(new ThreadStart(getLinkList)); 
    linkListThread.Start(); 
} 

void getLinkList() 
{ 
    List<string> linkList = new List<string>(); 
    // Your tasks 

    // Done 
    LinkListComplete(linkList); 
} 

void LinkListComplete(List<string> linkList) 
{ 
    if (InvokeRequired) 
    { 
     Invoke(new Action<List<string>>(LinkListComplete),linkList); 
     return; 
    } 

    foreach (String link in linkList) 
    { 
     txtOutput.Text += link; 
    } 
}