我遇到的问题是在一个不同的线程上处理一个事件。处理事件的对象不是UI对象,因此我不能使用Invoke来执行委托并自动切换到UI线程以进行事件处理。
情况如下:我有一个包含多个表单的MDI应用程序。每个表单都有自己的控制器类,用于处理耦合表单和外部对象之间的通信。所有表单都是概述或详细信息表单(例如ContactsOverview& ContactDetail)并共享相同的数据。
在发生错误的情况下,表单以类似向导的顺序显示,例如详细信息表单后面是概述表单。在详细信息表格中,以下概述表格中使用的数据已更改,在切换到概览表单之前,需要在此处反映这些更改。从详细信息表单中引发事件,并由控制器处理概述表单,该表单执行必要的UI元素更新。
现在,在详细信息表单中保存更改的数据可能需要一段时间,因此UI必须保持响应,并且仍然可以使用应用程序的其他部分。这就是为什么后台工作者开始处理这个问题的原因。保存数据时,将在后台线程上引发事件。概述的控制器处理这个,但是当UI需要更新时,当然存在跨线程异常。
所以我需要的是一种在UI线程上引发事件的方法,但由于UI元素上没有发生处理,因此无法使用Invoke自动切换线程。
从网上搜索,我找到了一种可能的解决方案,即使用生产者/消费者模式。但据我所知,这将要求每个控制器在单独的线程中监听事件队列。由于它是一个MDI应用程序,理论上可以有任意数量的控制器表单,我不想启动那么多线程。
欢迎任何建议。如果有办法避免全部使用背景工作,那么这也是一个合适的解决方案。
感谢阅读,
凯文
答案 0 :(得分:1)
您可以使用SynchronizationContext,特别是SynchronizationContext.Current将消息发布到主同步上下文(这是GUI应用程序的主线程)。
不幸的是,我对这个课程及其用法知之甚少,说这是一个明确的解决方案。特别是,如果您不需要主线程来处理您的事件,而不是特定的线程,我不知道您应该怎么做。
也许WindowsFormsSynchronizationContext类可以帮助你,它有一个公共无参数构造函数,我认为它可能会将它与当前线程关联,所以如果你从拥有控制器的线程构造该对象,并将它提供给后台线程代码,它可能会工作。
答案 1 :(得分:0)
您可以在UI元素订阅的背景对象上创建一个事件。在事件处理程序(订阅 - 因此它是窗口代码的一部分)中,您可以进行调用。这就是我解决这个问题的方法。
答案 2 :(得分:0)
你可以尝试这个flag,但我不认为这是最好的主意,只是一个解决方法。
您还可以尝试在非图形线程中实例化发布对象,这可能会解决您的问题。
还有一件事,你不能让你的UI组件处理RunWorkerCompleted(带间接)吗?