简体   繁体   English

等待后台工作人员完成而不会阻塞UI线程

[英]Waiting for a background worker to finish without blocking UI thread

I have an application that needs to wait for a background worker to finish before moving on. 我有一个应用程序,需要等待后台工作人员完成后才能继续。 The background worker is in charge of writing some values to a USB device that initializes it. 后台工作者负责将一些值写入初始化它的USB设备。 The problem with the background worker is that my main program can try to access the USB device before the background worker is finished initializing. 后台工作程序的问题在于,我的主程序可以在后台工作程序完成初始化之前尝试访问USB设备。

While the background worker is working, the UI thread shows a "please wait" with an animated progress bar. 在后台工作程序工作时,UI线程显示带有动画进度条的“请稍候”。 The progress bar does not reflect how far along the background worker is, it merely 'spins'. 该进度条反映多远沿后台工作,它仅仅是“旋转”。

I have read a few questions that say not to use a background worker, because I really don't want it to run asynchronously (which is true), however, without using a background worker, my "please wait" dialog blocks and doesn't show the animation. 我读过一些问题,说不使用后台工作程序,因为我真的不希望它异步运行(这是对的),但是,如果不使用后台工作程序,我的“请稍候”对话框将阻止并且不会t显示动画。 I have also read a lot that tells me to only use one UI thread, which then supports the use of a background worker. 我也读了很多书,告诉我只能使用一个UI线程,然后该线程支持使用后台工作程序。

I have also tried to put the "please wait" spinner in a separate thread, but that introduces complexities and strange race conditions where the "please wait" windows tries to close before it has opened. 我还尝试将“请等待”微调器放在单独的线程中,但这会带来复杂性和奇怪的竞争条件,在这种情况下,“请等待”窗口会在打开之前尝试关闭。

What is the right way to go about this? 解决这个问题的正确方法是什么?

That's exactly what BackgroundWorker is designed for. 这正是BackgroundWorker设计的目的。 Although there are other ways to accomplish this, what you're doing is just fine. 尽管还有其他方法可以完成此操作,但是您所做的就很好。

I have read a few questions that say not to use a background worker 我读了一些问题,说不使用后台工作者

Don't really know why people have suggested not to use this as it's exactly what it was designed for. 真的不知道为什么人们建议不要使用它,因为它正是为它设计的。 Ideally what you would want to do is show a modal dialog with the spinner and an option to cancel, that way the user is blocked by the UI from interrupting the write process on the USB. 理想情况下,您想要做的是显示一个带有微调框和取消选项的模式对话框,这样,UI会阻止用户中断USB上的写入过程。

Even simply disabling the buttons during the write process could suffice. 即使在写过程中简单地禁用按钮也足够了。

I think there are two separate issues you are trying to resolve. 我认为您正在尝试解决两个单独的问题。

The first one is how to prevent the Main (UI) thread accessing an uninitialized USB device. 第一个是如何防止主(UI)线程访问未初始化的USB设备。 The other one is handling the "Please Wait" spinner dialog. 另一个正在处理“请稍候”微调器对话框。

My suggestions are: 我的建议是:

  1. Keep the BackgroundWworker handling the USB device initialization. 保持BackgroundWworker处理USB设备初始化。
  2. Add a boolean field to your class, to flag when the USB device completed initialization eg 向您的班级添加一个布尔字段,以在USB设备完成初始化时进行标记,例如

    private volatile bool _usbDeviceInited = false;

  3. The last thing your background worker will do, is set this flag to true . 您的后台工作者要做的最后一件事就是将此标志设置为true

  4. Centralize access to the USB device by means of a property. 通过属性集中访问USB设备。 The getter method can inspect the boolean field and return a null value (or raise an exception if you prefer) if USB initialization has not completed. 如果USB初始化未完成,则getter方法可以检查布尔值字段并返回一个空值(或根据需要引发异常)。
  5. Modify your code to check if null is being returned (or handle the exception, if you chose to raise one) by the property giving access to the USB device, meaning it is not ready for use. 修改代码以检查是否可以通过提供对USB设备的访问权限的属性返回null(或者处理异常,如果您选择加一,则返回该异常),这表明该USB设备尚未准备好使用。 You can handle this condition to alert the user that the USB device is not ready. 您可以处理此情况,以警告用户USB设备尚未就绪。

The previous steps are one way to solve your first issue. 前面的步骤是解决第一个问题的一种方法。 Now, for the spinner. 现在,对于微调器。

I suggest suscribing to the RunWorkerCompleted event of your BackgroundWorker . 我建议您使用BackgroundWorkerRunWorkerCompleted事件。 If your BackgroundWorker was created from the main UI thread, the event will fire in the main UIThread (meaning it's safe to interact with the user interface elements). 如果您的BackgroundWorker是从主UI线程创建的,则该事件将在主UIThread中触发(这意味着与用户界面元素进行交互是安全的)。 From there you can simply close and dispose your "Please Wait" dialog. 从那里您可以简单地关闭并放置“请稍候”对话框。 You should also check the AsyncCompletedEventArgs.Error property to ensure no error condition was raised from the BackgroundWorker thread while initializing the USB device. 您还应该检查AsyncCompletedEventArgs.Error属性,以确保在初始化USB设备时,不会从BackgroundWorker线程引发任何错误情况。

EDIT: I have just read that your app may run a script that immediately tries to access the USB device. 编辑:我刚刚读到您的应用程序可能会运行一个脚本,该脚本立即尝试访问USB设备。 Using the pattern I suggested, you may "poll" the property before running the script until it returns a value different than null like this: 使用我建议的模式,您可以在运行脚本之前“轮询”属性,直到它返回的值不同于null,如下所示:

bool timedOut = false;
DateTime timeout = DateTime.Now.AddSeconds(timeoutSeconds);
while ( MyClass.MyUsbDevice == null ) {
   if( DateTime.Now > timeout ) {
      timedOut = true;
      break;
   }
   Thread.Sleep(0); // Avoid pegging the CPU, yield it to other processes
}

if( !timedOut ) {
   // run the script
} else {
   // Handle timeout
}

Good Luck! 祝好运!

将必须在BackgroundWorker完成后执行的部分(脚本)放入BackgroundWorkerRunWorkerCompleted事件处理程序中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM