2010-03-10 36 views
1

我在处理引发它的其他线程上的事件时遇到问题。但是,处理事件的对象不是UI对象,所以我不能使用Invoke执行委托并自动切换到用于事件处理的UI线程。非UI对象上的跨线程事件处理

的情况如下:我有一个包含多种形式MDI应用程序。每个表单都有自己的控制器类,用于处理耦合表单和外部对象之间的通信。所有表格都是概览或详细表格(例如ContactsOverview & ContactDetail)并共享相同的数据。

在发生错误的形式出现在类似于向导的序列的情况下,说详细信息表单之后的概述表格。在下面的概览表格中使用的详细表格数据发生了变化,在切换到概览表格之前,需要在这些表格中反映出这些变化。从详细信息表单中引发事件,并由控制器为完成必要的UI元素更新的概览表单处理。

现在详表的更改数据的保存可能需要一段时间,因此是必要的UI会保持应用程序的响应和其他部分仍可使用。这就是后台工作者开始处理这个问题的原因。数据保存后,事件在后台线程中引发。概述的控制器处理这个,但是当UI需要更新时,当然存在跨线程异常。

所以我需要的是一种方法来提高UI线程上的事件,但由于处理不UI元素上发生的没有办法来自动切换使用调用线程。

从网络上搜索,我发现这是使用生产者/消费者模式的一个可能的解决方案。但是,据我所知,这需要每个控制器在单独的线程中监听一系列事件。由于它是一个MDI应用程序,理论上可以有任何形式的控制器,我不想启动那么多的线程。

欢迎任何建议。如果有一种方法可以避免使用背景工作者,那么这也是一个合适的解决方案。

感谢您的阅读,

凯文

回答

1

您可以使用SynchronizationContext,特别是SynchronizationContext.Current将消息发布到主同步上下文(这是GUI应用程序的主线程)。

不幸的是我不够了解类及其用法说这是一个明确的解决方案。特别是,如果您不需要主线程来处理您的事件,而是需要特定的线程,我不知道该怎么办。

也许WindowsFormsSynchronizationContext类可以帮助你,它有一个公共无参数的构造函数,我想它可能会将它与当前线程相关联,所以如果你从拥有控制器的线程构造该对象并给它到后台线程代码,它可能工作。

+0

谢谢,我会研究它。 – kwe 2010-03-10 09:48:35

+0

正是我想建议... – 2010-03-10 09:48:39

+0

在阅读这篇有用的文章 - http://msmvps.com/blogs/manoj/archive/2005/11/03/74120.aspx - 我很确定这种方法将能够解决我的问题。根据我的理解,您可以使用SynchronizationContext来保存对调用线程的引用,并且在后台线程中的处理完成后,可以使用SynchronizationContext中的引用在调用线程上启动事件。我已经在一个快速演示项目中测试过它,它可以工作。再次感谢! – kwe 2010-03-10 10:31:20

0

您可以对背景objec的UI元素订阅的事件。在事件处理程序(订阅的 - 所以它是窗口代码的一部分),你可以然后调用。这是我解决这个问题的方法。

+0

问题是UI元素没有订阅事件,UI元素的控制器是,它只是一个普通的c#类,并没有invoke方法。 – kwe 2010-03-10 09:38:06

+0

那么......在这种情况下,我会说控制器完全脱离UI元素不起作用,或者;) 也许控制器应该得到一个指向表单的指针,所以它可以调用... – TomTom 2010-03-10 10:12:16

+0

那么应用程序是在第三方框架上开发的,并且改变关于UI和控制器之间关系的任何事情都会导致代码更改的海啸。但它会为我们节省很多麻烦,如果它像你的建议:) – kwe 2010-03-10 10:47:51

0

你可以试试这个flag但我不认为这是最好的想法,只是一个解决办法。

您也可以尝试在非图形线程中实例化发布对象,这可能会解决您的问题。

还有一件事,你不能让你的UI组件处理RunWorkerCompleted(与indirections)?

+0

您的意思是从UI元素启动后台工作器,然后通过RunWorkerCompleted中的UI元素访问UI线程? – kwe 2010-03-10 09:56:04

+0

划伤第一条评论,我明白你的意思了。问题在于数据的保存会自动触发事件的发生,并且分离该部分将是相当多的工作,而不是使用我接受的答案SynchronizationContext。但它仍然是一个可行的解决方案。谢谢。 – kwe 2010-03-10 10:45:01