以两种形式作为不同的线程运行(或者至少有两种形式“并行”运行)

本文关键字:运行 两种 或者 并行 线程 | 更新日期: 2023-09-27 18:25:28

我想做以下(c#)

  • 我有一张表格,叫Form1吧
  • Form1创建Form2
  • Form2的构造函数被执行(GUI,变量..)。Form2的最后一条指令是:创建和显示Form3
  • Form2包含Label1
  • Form2创建Form3并将其自身的引用传递给Form3
  • Form3多次编辑(Form2的)标签1(假设为100)

这没关系…一切都正常,但。。问题是:Form3运行所有操作需要很长时间(假设为10秒)。最后(同时)Form2和Form3都显示了,但我希望Form2在Form3之前可见,因为我希望在执行Form3操作(包括在Form2上编辑标签1)时,Form2显示label1的每次更新(如"Doin:operation 1",然后"Doin:operation 2",依此类推)。

我还尝试在Form2上制作一个按钮(Button1),定义Button1_nClick()事件,并用"创建并显示Form3"来实现其内容。但是,当我单击按钮1时,Form2"消失"(就像Windows应用程序被阻止并变为"暂停"时一样),它只在Form3出现的同一时刻显示最终标签("操作:100")。

我的问题摘要:-->我有3张表格

  • 表格1
  • 表格2(带标签1)
  • Form3(在Form2中编辑Label1)

-->应该发生什么:

  • Form1创建并显示Form2
  • Form2创建并显示Form3
  • Form3进行各种操作(如创建列表、排序等),每次操作都会更新Form2中的Label1(用户必须查看更新过程)

所有Form2操作都是从Form2构造函数中调用的函数调用的,如:Form2_Constructor()=>调用makeOperation()-->makeOperations()=>调用Operation1(),然后调用Operation2(),最后调用Operation3(),其中每个OperationX()包含一个循环(比如说30次迭代),执行一些操作并调用Form2.setLabel1("操作名称");

我的想法(正如标题所说)是制作两条不同的线。。..或者至少找到一种方法,让两个窗体在"并行模式"下运行(这样,当Form3执行操作时,Form2就不会空闲)。

知道怎么解决这个问题吗?

以两种形式作为不同的线程运行(或者至少有两种形式“并行”运行)

如果您真的想要两个不同的表单在不同的线程上运行,那么您将需要创建另一个通过Application.Run运行消息循环的线程。但是,不建议采用这种方法。这可能会导致奇怪的问题,并且会使两种不同的表单不方便相互访问,因为从一种表单到另一种表单的所有访问都需要使用Control.Invoke进行封送处理。

我建议使用单一的UI线程。将当前由Form3执行的长时间运行的代码获取到工作线程中。随着工作线程的进展,您可以缓慢地将结果发布到Form3。可以通过以下两种方式之一将结果发布到Form3

  • 让工作线程通过调用InvokeBeginInvoke将结果推送给Form3
  • Form3轮询共享数据结构以获取工作线程发布的结果

那些监视我答案的人已经知道我要推荐哪一个:UI线程轮询结果的稍后方法。它具有以下优点。

  • 它打破了Control.Invoke强加的UI和工作线程之间的紧密耦合
  • 它将更新UI的责任放在UI线程上,不管怎样,它都应该属于该线程
  • UI线程可以决定更新的时间和频率
  • UI消息泵没有被溢出的风险,就像工作线程启动的封送处理技术一样
  • 工作线程在继续执行下一步之前不必等待更新已执行的确认(即,在UI和工作线程上都可以获得更高的吞吐量)

如果Form3当前正在执行的工作无法轻松地移动到工作线程(也许它在大多数时候都在操纵UI控件,而这只能通过承载表单的UI线程来完成),那么您将需要放慢执行此工作的速度,以便表单有更多的时间响应用户输入。这意味着你将被迫做出一些牺牲。例如,您可能需要一次只填充一百行,而不是用数千行填充网格,并提供某种分页行为,允许用户移动到下一个一百行。

通常,您应该将所有UI保留在主线程上,并在后台执行长时间运行的任务。

根据您使用的.Net版本以及后台工作的内容,您可能会使用BackgroundWorker、ThreadPool或.Net 4.0 Task类。

无论你使用哪一个,当你更新UI中的状态时,你都必须使用控件的Invoke方法来更新它,否则你会遇到一个异常,即试图从一个没有创建控件的线程更新控件。

有许多关于后台线程和更新UI的文章。

这是一篇关于.Net 4任务和WinForms的文章(完全公开,这是我的文章)。

这是一个模拟您所描述的基本VS项目——三个表单相互启动,第三个表单执行后台工作并更新表单2上的状态(后台工作由BackgroundWorker控件完成)。

是的。坐下来编程。启动另一个线程,在其中创建另一个表单并启动调度器。然后使用标准的消息传递语义在表单之间进行对话。