我正在为另一个程序编写插件,该程序使用本地程序打开一系列文件来提取一些数据。我遇到的一个问题是这个进程需要很长时间,而我希望保持用户界面不会挂起。此外,我还想在进程完成之前让用户有能力取消进程。以前我使用了一个后台工作器来处理这种情况,但在这种情况下,我认为BackgroundWorker不适用。
通过我正在使用的API创建插件,可以通过继承IAPICommand接口来创建自定义命令。该接口包括一个Execute(Application app)方法。然后实例化该类,并在用户在程序中调用自定义命令时由程序调用Execute()方法。
当调用Execute()方法时,传递了对当前Application对象的引用,正是这个应用程序对象用于打开要从中提取数据的文件。然而,应用程序实例无法在除原始Execute()线程之外的其他线程请求时打开文档。
因此,通常UI将存在于主线程上,而耗时的数据提取将在辅助线程上执行。但在这种情况下,必须在主线程上执行数据提取,并且我需要为UI创建辅助线程。
以下是代码的简化版本。
class MyCommand:IAPICommand
{
public void Execute(Application app) // method from IAPICommand
{
Thread threadTwo= new Thread(ShowFormMethod);
threadTwo.Start();
}
public void ProcessWidget(Widget w, Application app)
{
//uses an App to work some magic on C
//app must be called from the original thread that called ExecuteCommand()
}
//method to open custom form on a seperatethread
public void ShowFormMethod()
{
MyForm form = new MyForm();
form.ShowDialog();
}
}
这是一个流程图,展示了我认为这个问题应该如何解决。
alt text http://dl.dropbox.com/u/113068/SOMLibThreadingDiagram.jpg
- 这个图表有意义吗?如果有的话,我是否采取了正确的方法来解决这个问题?
- 一旦主线程启动UI线程,我希望它等待用户选择要处理的小部件或通过关闭窗体(图表中的红色数字)来结束命令。我如何让主线程等待,并且如何触发它继续进行处理或在UI线程结束时继续到最后?我想我可以让主线程等待一个监视器锁。然后UI线程会填充要处理的小部件的静态列表,然后脉冲主线程以触发处理。当窗体关闭时,UI线程还会脉冲主线程,如果要处理的小部件列表为空时脉冲主线程,那么主线程将知道继续到命令的最后。
- 如何允许主线程向UI线程传递小部件处理的进度或完成情况(图表中的黄色箭头)?我只需要使用Form的BeginInvoke()方法来实现吗?
- 如何允许UI线程取消小部件处理(图表中的绿色箭头)?我想我可以设置一个静态布尔标志,在处理每个小部件之前检查它是否被取消了?