我的后台工作者仍然阻止我的 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 的情况下调用该方法?
不知道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 实例,但立即丢弃该线程并保留引用。