我正在尝试以MVP风格执行Windows窗体应用程序 - 并且之前没有做过多次线程处理 - 让所有人感到困惑。
我的用户界面是一组非常简单的表单。每个表单都实现一个接口,并包含对位于业务逻辑层中的中介类的引用,反之亦然。 因此简化图如下所示:
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的线程并让它们相互通信可能真的有帮助。
答案 0 :(得分:2)
你有没看过BackgroundWorker班?它非常适合在后台类型过程中进行大量简化处理,并为可以列出的事件提供GUI显示进度。
答案 1 :(得分:0)
您可以从另一个线程操作WinForms控件,但您需要使用Control.Invoke()
,并且由于上下文切换,您将为每个跨线程调用支付相当大的性能损失和相关的幕后CLR伏都教。
如果要将GUI与多线程应用程序中的业务逻辑和基础结构代码隔离,我建议使用线程安全队列切换到消息传递模型。每当下层需要告诉GUI执行某些操作时,他们会将消息对象放入队列中,GUI元素会定期通过Forms.Timer
进行轮询。这对于大型处理器密集型应用程序尤其有效,因为您可以通过调整更新计时器频率来在一定程度上限制GUI更新的处理需求。
对于以相反方式返回的调用(GUI - &gt;下层),您只需从GUI代码调用调解器方法,只要这些调用快速返回 - 您需要非常小心延迟GUI线程,因为整个应用程序的响应性将受到影响。如果你有一些难以快速返回的调用,你可以用另一种方式添加第二个队列。