我的后台工作者仍然阻止我的 UI

本文关键字:我的 UI 后台 工作者 | 更新日期: 2023-09-27 18:36:53

我有一个耗时的方法,在一个被

埋藏在一个我没有来源的.dll中的类中。我不想在调用此方法时阻止 UI。我一直在尝试使用BackgroundWorkers来做到这一点。我从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 的情况下调用该方法?

我的后台工作者仍然阻止我的 UI

有没有人建议如何在不阻止 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 线程上运行的线程亲和性规则。

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

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

这听起来会有所帮助吗? 您仍然可以将其全部封装到单个后台辅助角色类中。

我正在开发一个 VB.net 应用程序,在与安捷伦设备通信时遇到了同样的问题。 这是我解决它的方法:

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 实例,但立即丢弃该线程并保留引用。