2

我正在尝试以 MVP 风格做一个 Windows 窗体应用程序 - 之前没有对线程做太多工作 - 我感到很困惑。

我的 UI 是一组非常简单的表单。每个表单都实现了一个接口并包含对位于业务逻辑层中的中介类的引用,反之亦然。所以简化图如下所示:

CheckInForm : ICheckIn                      <-------> CheckInMediator : ICheckInMediator
----------------------------------------------------------------------------------------
CheckInForm.Show()                          <--------
                                            --------> AttemptCheckIn(CheckInInfo)
CheckInForm.DisplayCheckInInfo(DisplayInfo) <-------- 
                                            --------> CompleteCheckIn(AdditionalCheckInInfo)
  PleaseWaitDialog.Show()                   <--------
  PleaseWaitDialog.Close()                  <--------
CheckInForm.Close()                         <--------

如您所见,中介类控制 UI,告诉它何时显示数据、启动、关闭等。它们甚至表示模式对话框何时出现以及何时关闭(即上面的 PleaseWaitDialog)。 UI 所做的是在屏幕上显示数据并将输入中继回中介。

这种架构很好且解耦,并且非常容易测试和原型化。现在我将它们放在一起,但是我开始遇到线程问题。例如,如果我希望我的 PleaseWaitDialog 在 CheckInForm 上显示为模式表单(使用 ShowDialog()),直到由中介控制的计时器计数 5 秒(请记住,这是一个简化)我会得到一个跨线程错误如果我从计时器的回调中调用 PleaseWaitDialog.Close() 。同样,如果我有一个模式对话框阻止用户与 UI 交互,我不希望它阻止业务层中的活动,除非我另有说明(例如使用确认对话框)。

我想我想做的是在主线程上运行中介和业务逻辑,在一个完全独立的线程上运行 UI,我的第一个问题是这样做有意义吗?

我的第二个问题是,我该如何做一些事情,比如让一个类在一个单独的线程中运行?我如何让两者沟通?我正在阅读 .NET 线程,但我有一个截止日期和一些示例,说明如何在主线程上生成一个包含 UI 的线程并让它们的对象相互交谈真的很有帮助。

4

2 回答 2

2

您是否查看过BackgroundWorker类?它非常适合在后台类型程序中进行大量简化处理,并提供可以列出的事件以使您的 GUI 显示进度。

于 2008-10-02T22:09:59.733 回答
0

可以从另一个线程操作 WinForms 控件,但是您需要使用Control.Invoke(),并且由于上下文切换和关联的幕后 CLR voodoo,您将为每个跨线程调用付出相当大的性能损失。

如果您想在多线程应用程序中将 GUI 与业务逻辑和基础架构代码分离,我建议切换到使用线程安全队列的消息传递模型。每次下层需要告诉 GUI 做某事时,它们都会将消息对象放入队列中,GUI 元素会通过Forms.Timer. 这对于大型、处理器密集型应用程序特别有效,因为您可以通过调整更新计时器频率在一定程度上限制 GUI 更新的处理需求。

对于以其他方式返回的调用(GUI -> 较低层),您可以只从 GUI 代码调用中介方法,只要这些调用相当快地返回 - 您需要非常小心延迟 GUI 线程,因为整个应用程序的响应能力将受到影响。如果您有一些难以足够快地返回的呼叫,您可以添加另一个队列。

于 2008-10-03T13:16:07.597 回答