我的BackgroundWorker仍然阻止我的UI

时间:2012-06-12 18:29:29

标签: c# wpf dll user-interface backgroundworker

我在一个埋藏在.dll中的类中有一个耗时的方法,我没有源代码。我在调用此方法时不想阻止UI。我一直在尝试使用BackgroundWorker来做到这一点。我从btn_Click事件处理程序调用RunWorkerAsync。当我在工作线程之外创建了dllClass实例(如下所示)时,UI会冻结,直到操作完成。该操作还会阻止计时器滴答作响。

public static dllClass dllClassInstance = new dllClass();

void worker1_DoWork(object sender, DoWorkEventArgs e)
{
    dllClassInstance.TimeConsumingMethod();
}

另一方面,如果我在工作线程中实例化类(如下一个代码段),它就会按预期工作。

void worker1_DoWork(object sender, DoWorkEventArgs e)
{
    dllClass dllClassInstance = new dllClass();

    dllClassInstance.TimeConsumingMethod();
}

使用后者的问题是我需要访问该特定worker之外的类实例,因为我必须在耗时的方法之前和之后调用其他方法。我还尝试通过e.Argument将类实例传递给BackgroundWorker,但它也导致UI冻结。有没有人建议如何在不阻止UI的情况下调用该方法?

4 个答案:

答案 0 :(得分:3)

  

有没有人建议如何在不阻止用户界面的情况下调用该方法?

在不知道dllClass内发生了什么的情况下,无法确定。

通常,这两种代码都不会导致UI冻结。我怀疑dllClass正在捕获其构造函数中的当前SynchronizationContext,并在TimeConsumingMethod内部使用它,导致阻塞。如果是这种情况,您可能会在DoWork处理程序中构造该类,但是将其作用于该类,这可能会起作用。但是,如果它正在捕获同步上下文,则该类可能具有线程关联性,并且期望在UI线程上运行。

您可以尝试在处理程序中构建实例,如下所示:

public dllClass dllClassInstance;

void worker1_DoWork(object sender, DoWorkEventArgs e)
{
    dllClassInstance = new dllClass(); // Construct here
    dllClassInstance.TimeConsumingMethod();
}

这可能有用,但正如我所说,它可能有其他副作用。我会验证dllClass没有线程关联规则,要求它在UI线程上运行。

答案 1 :(得分:1)

这可能是因为你的dllClass。除非有人想确保在同一个线程中处理实例上的所有调用,否则不应该发生这种情况。如果dllClass在其构造函数中接受调度程序,然后TimeConsumingMethod通过该调度程序调用实际处理,那么您将看到冻结的UI。

答案 2 :(得分:0)

正如里德指出的那样,如果不知道那个班级的内部是什么,可能很难真正解决。但是,如果你有其他东西需要加载/准备,设置,我会让你的后台工作者类“ReportsProgress”= true,当它启动时,立即调用一个方法来获取和/或准备基于ex的其他设置:进度为1(开始),然后,执行长进程的其他元素,然后报告进度值为99(结束)并从中进行清理。

这听起来有点像帮助吗?您仍然可以将它全部封装到一个后台工作者类中。

答案 3 :(得分:0)

我正在研究VB.net应用程序,并遇到与Visa Com 3.0驱动程序相同的问题,以便与安捷伦设备进行通信。以下是我解决它的方法:

Dim task = New Threading.Tasks.Task(Of dllClass)(Function()
                                                     Return New dllClass()
                                                 End Function)
task.Start()
task.Wait()

public static dllClass dllClassInstance = task.Result;

void worker1_DoWork(object sender, DoWorkEventArgs e)
{
    dllClassInstance.TimeConsumingMethod();
}

基本上我在一个新线程中创建我的dllClass实例,但是立即丢弃该线程并保留引用。