2

我在一个隐藏在我没有源代码的 .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();
}

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

4

4 回答 4

3

有没有人建议如何在不阻塞 UI 的情况下调用该方法?

不知道内部发生了什么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 线程上运行。

于 2012-06-12T18:35:12.103 回答
1

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

于 2012-06-12T18:35:57.310 回答
0

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

这听起来会有所帮助吗?您仍然可以将其全部封装到一个后台工作人员类中。

于 2012-06-12T18:40:58.053 回答
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 实例,但立即丢弃该线程并保留引用。

于 2013-06-26T17:24:01.533 回答