在异步无返回值的 DoWork 事件之前,RunWorkerCompleted 已经被触发。

3

我正在使用后台工作程序进行BLE RSSI级别测试。

我的问题是RunWorkerCompleted事件会在DoWork完成操作之前立即触发。

大部分DoWork事件操作是创建一个广告观察器并等待来自蓝牙低功耗设备的信号。信号水平将从主线程更新,结果处理将在后台工作程序中进行。

这是我调用后台工作程序的时候:

 ...
  worker = new BackgroundWorker();
        worker.DoWork += callTestBLE;
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        worker.RunWorkerAsync(RSSI_Label);
  }

事件处理程序:

private async void callTestBLE(object sender, DoWorkEventArgs e)
    {
            BluetoothLEAdvertisementWatcher watcher1 ;
            BluetoothLEAdvertisementFilter advertisementFilter1;
            int rssiRetries1 = RSSIRETRIES;
            RssiValue = "";

            advertisementFilter1 = new BluetoothLEAdvertisementFilter();
            try
            {
                advertisementFilter1.Advertisement.LocalName = myUswm.getAdvetrismentName();
                checkRSSI = true;
            }
            catch (Exception) { checkRSSI = false; return; }

            watcher1 = new BluetoothLEAdvertisementWatcher(advertisementFilter);
            watcher1.ScanningMode = BluetoothLEScanningMode.Active;
            watcher1.Received += OnAdvertisementReceived;
            // Wait 5 seconds to make sure the device is really out of range
            watcher1.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(5000);
            watcher1.SignalStrengthFilter.SamplingInterval = TimeSpan.FromMilliseconds(2000);

            try
            {
                watcher1.Start(); 
                await testBLEAsync();
                if (myUswm.getConnectionStatus() == DISCONNECTED)
                {
                    checkNextUUTClick(new object(), new RoutedEventArgs()); return;
                }
                for (int i = 0; i < 5; i++)
                {
                    // if (RssiSamplesNum <= 0 || --rssiRetries < 0)
                    if (RssiSamplesNum <= 0 || --rssiRetries1 < 0)
                    {
                        //serviceList.Clear();
                        watcher1.Stop();
                        rssiRetries1 = RSSIRETRIES;
                        RssiSamplesNum1 = numOfAdvertismentSamples;
                        break;
                    }
                    else
                    {
                       ((Label)e.Argument).Content = RssiValue;
                        /*RSSI_Label.Dispatcher.Invoke(new Action(() =>
                        { RSSI_Label.Content = RssiValue; }));*/
                    }
                    Thread.Sleep(2000);
                  }    
            }
    catch (Exception err) { }
    }

    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
       finalizeBleTest();
    }

感谢任何帮助!

在后台工作线程中,您不应与UI元素进行交互(或调用MessageBox.Show),因为这不是UI线程,会引起问题。 - undefined
你是对的,代码已经被编辑过了。 - undefined
3
async void 应该用于“Fire & Forget”代码,因为调用代码无法跟踪完成情况。所以我建议您的 DoWork 方法不应该是 async 的。可以使用 BackgroundWorker 或者使用 async/await,但一般情况下不要尝试将它们结合在一起。 - undefined
2个回答

8

我同意其他答案的观点,BackgroundWorkerasync/await不兼容。然而,我不同意最简单的解决方案是放弃async,改用BackgroundWorker。在我看来,更优秀的解决方案(也会导致更简单的代码)是放弃BackgroundWorker,改用async;具体而言,是用更优秀的Task.Run替换过时的BackgroundWorker

// `worker` is now `Task`.
await Task.Run(() => callTestBLE());
finalizeBleTest();

callTestBLE 的签名应该是 async Task,而不是 async void


3
这里的问题涉及到asyncawait。BackgroundWorker有点过时,不支持异步代码。因此,当您等待testBLEAsync调用时,callTestBLE方法会完成,并在此时调用RunWorkerCompleted事件,而实际代码会继续在后台工作。
因此,最简单的解决方案是完全从代码中删除async/await,这样一切都应该按预期工作,或者,您可以使用任务和任务连续性重写代码。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接