在Windows窗体应用程序中的不同线程中分离GUI和逻辑

时间:2009-08-26 09:53:57

标签: c# .net winforms multithreading user-interface

在Windows窗体应用程序中,我想将GUI与逻辑分开。用户请求很复杂并且涉及通信,因此我不希望它依赖于GUI线程。结构应该是这样的:

        GUI -----> splash screen ---------> User Form --------------> ...
              |                        #
              | create Manager thread  | Show this Form
              #                        |
    Manager -----> Check user type -------> Wait for user command --> ...

对于像这样的设计,您有哪些建议,指南或模式?这是正确的选择吗?谢谢!

修改 Manager线程应该控制GUI而不是相反。此外,Manager线程应在所有应用程序时间内生效。

3 个答案:

答案 0 :(得分:4)

传统上这样的工作是使用BackgroundWorker

完成的

基本上它是一个简单的类,它使您能够在工作线程上执行函数,然后在该函数完成后自动调用回UI线程。在运行该功能期间,UI被解锁并可以显示进度消息,或处理其他用户输入(例如取消)。

结果类似于你的模式,但是为每个任务创建并销毁了一个单独的线程(好吧,真的有池......)。

UI thread ---> Show splashscreen------------------->Show window-------
                      |                           |return to UI      |
                      | create background worker  |                  |
                      -> Process user ------------                   ->Perform query etc.

好的,根据您的评论:

你可以使用这样的模式,这是一个简单的事件案例。授予管理员UI访问权限,以便它可以对其执行方法调用,并在任务完成时注册事件(this link显示.NET中异步操作的两种主要模式)。在管理器内部,您需要维护一个可以在单个线程上按顺序执行的任务列表,并确保正确调用被调用以将结果返回到UI的事件,以便在主UI线程上运行(基本上重新创建后台工作者模式)。

我不确定你希望通过这样做获得什么,是否有理由将应用程序限制为两个线程?您是否担心创建后台工作者的成本?你需要某种查询队列系统吗?您问题中图表中的示例似乎并不需要这种模式的复杂性。

答案 1 :(得分:2)

您应该使用background worker来完成任务。

它有非常方便的事件。 DoWork和RunWorkerCompleted,非常方便。

您也可以尝试使用Threads,它们看起来像这样: (请记住,当您使用Threads时,如果您想使用UI Thread进行任何操作,则必须使用Invoke(),否则您将收到CrossThreadException)

private delegate void MyFunctionCaller();

//This will set up your worker thread and set it off
private void SetThreadToDoWork()
  {
  ThreadStart threadStart = new ThreadStart(DoWork);
  Thread MyThread = new Thread(threadStart);
  MyThread.Start();

  ShowSplashScreen();
  }

private void DoWork() 
  {
  DoMyWork();
  WorkCompleted();
  }

private void WorkCompleted()
{
if (InvokeRequired == true)
  {
  MyFunctionCaller InvokeCall = delegate { WorkCompleted(); };
  Invoke(InvokeCall);
  }
else
  {
  //Back to the UI thread now.
  }
}

OPs编辑

您可以在任何地方创建线程,一旦启动就可以完成多个功能。但请记住,如果您想完成UI线程只能完成的任何工作,您需要Invoke(),否则您将获得CrossThreadException。

答案 2 :(得分:1)

我开发了一个类似的项目。 GUI在不同的线程上启动管理器。 Manager有一些方法可以从GUI获取命令。 GUI正在监听Manager的事件,因此仅在Manager启动事件时才会更新。 为了避免交叉线程,我习惯于“调用”方法