Я использую ExcelDNA для чтения данных из рабочих книг (используя C API) внутри асинхронного диалога WPF. Чтобы это работало, я использую делегат QueuedAsMacro. Проблема в том, что я хочу обновить индикатор выполнения, и поэтому я пытаюсь использовать BackgroundWorker (когда я новичок в многопоточности), но это не удается, выдавая следующую ошибку:
Эта операция уже вызывала OperationCompleted, и дальнейшие вызовы являются недопустимыми.
Поиск, я понял, что обычно это происходит, когда есть несколько экземпляров BackGroundWorker или какой-либо параллельный процесс потока,что не в моем случае.
Следует фрагмент кода:
private void MyMainFunction(object sender, DoWorkEventArgs e)
{
ExcelAsyncUtil.QueueAsMacro(
delegate
{
float i = 0;
foreach (wkbData iWbk in wkbsList)
{
ReadWorkbookData(iWbk );
i++;
(sender as BackgroundWorker).ReportProgress(Convert.ToInt16((i / wkbsList.Count) * 100)); //Update progress bar
}
});
}
Я также пытался использовать делегат Invoke (просто выстрел в темноте). Но результаты остаются прежними:
this.Dispatcher.Invoke(() => { (sender as BackgroundWorker).ReportProgress(Convert.ToInt16((i / wkbsList.Count) * 100)); });
Другими словами: выполняя некоторые тесты, я понял, что индикатор выполнения работает нормально, если я не использую ExcelAsyncUtil.QueueAsMacro. делегат.
Кроме того, как только QueueAsMacro отклоняет выполнение другим потоком, использование BackgroundWorker просто не соответствует моей проблеме, например, событие RunWorkerCompleted запускается беззавершение методов внутри ExcelAsyncUtil.QueueAsMacro.
Я совершенно уверен, что мне нужно найти способ связи потока QueuedAsMacro с потоком WPF, но я понятия не имею, как это сделать.
Любая подсказка?
Обновление благодаря некоторым новым тестам и исследованиям:
QueuedAsMacro позволяет обновлять индикатор выполнения непосредственно в потоке WPF, еслиВы используете Invoke делегат. (без необходимости использования какой-либо стратегии, такой как событие ProgressChanged BackgroundWorker).
Dispatcher.Invoke(() => MyProgressBarControl.Value = Convert.ToInt16((i / wkbsList.Count) * 100));
Тем не менее, обновляется только значение индикатора выполнения (сама панель не получает цветовой окраски).
Я только что случайно обнаружил, что использование BackgroundWorker просто для вызова основной функции (bgWorker.DoWork += MyMainFunction)
и непосредственного обновления индикатора выполнения дает ожидаемый результат: плавное выполнение, в том числе рисование.
Это действительно странно, и у меня нет объяснения этому. Я надеюсь, что кто-то может уточнить.
Заранее спасибо.