WPF BackgroundWorker Выполнение - PullRequest
1 голос
/ 30 мая 2010

Я некоторое время программировал на C # (я специалист по компьютерным наукам), и мне никогда не приходилось реализовывать многопоточность.

В настоящее время я создаю приложение для клиента, которое требует многопоточности для ряда операций.

Из-за характера соглашения между клиентом и провайдером я не могу опубликовать источник, с которым работаю. Код, который я разместил, в общем виде. Практически основная идея того, что я реализую, за исключением конкретного источника контента.

Первый фрагмент демонстрирует мою базовую структуру,

Класс Progress - это пользовательское окно прогресса, которое отображается в виде диалога для предотвращения взаимодействия с пользовательским интерфейсом.

В настоящее время я использую код для завершения вызовов базы данных на основе набора объектов в другой области кода приложения.

Например, у меня есть коллекция «Объектов» одного из моих пользовательских классов, для которых я выполняю эти вызовы базы данных от имени или по поручению. Моя текущая настройка прекрасно работает, когда я вызываю функцию «GeneralizedFunction» один и только один раз.

Что мне нужно сделать, так это вызвать эту функцию один раз для каждого объекта в коллекции. Я пытался использовать цикл foreach для итерации по коллекции, затем я попытался использовать цикл for.

Для обоих циклов результат был одинаковым. Асинхронная операция выполняется точно так, как требуется для первого элемента в коллекции. Это, однако, единственный, на который он работает. Для каждого последующего элемента окно прогресса (мое собственное окно) отображается и сразу закрывается.

Что касается вызовов базы данных, то вызовы для первого элемента в коллекции являются единственными, которые успешно завершаются. Все остальные не предпринимались.

Я перепробовал все, что я знаю и не знаю, но я просто не могу заставить его работать.

Как мне заставить это работать для всей моей коллекции?

Любая помощь очень ценится.

Progress progress;

BackgroundWorker worker;

// Cancel the current process
private void CancelProcess(object sender, EventArgs e)
{
 worker.CancelAsync();
}

// The main process ... "Generalized"
private void GeneralizedFunction()
{
 progress = new Progress();
 progress.Cancel += CancelProcess;
 progress.Owner = this;

 Dispatcher pDispatcher = progress.Dispatcher;

 worker = new BackgroundWorker();
 worker.WorkerSupportsCancellation = true;

 object[] workArgs = { arg1, arg2, arg3};

 worker.DoWork += delegate(object s, DoWorkEventArgs args)
 {
  /* All main logic here

  */

  foreach(Class ClassObject in ClassObjectCollection)
  {
   //Some more logic here

   UpdateProgressDelegate update = new UpdateProgressDelegate(updateProgress);

   pDispatcher.BeginInvoke(update, arg1,arg2,arg3);
   Thread.Sleep(1000);
  }
 };
 worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
 {
  progress.Close();
 };

 worker.RunWorkerAsync(workArgs);
 progress.ShowDialog();
}

public delegate void UpdateProgressDelegate(arg1,arg2,arg3);

private void updateProgress(arg1,arg2,arg3)
{
 //Update progress
}

Ответы [ 2 ]

1 голос
/ 30 мая 2010

ОК, так что у вас есть фоновый процесс, запущенный в обработчике DoWork. Этот поток порождает ряд других потоков (с BeginInvoke) и затем спит 1 секунду. (почему сон (1000)?)

Кажется, не было никакой попытки дождаться завершения потоков UpdateProgressDelegate после цикла for. Поэтому вы будете вызывать progress.Close();, когда некоторые из этих pDispatchers все еще выполняются.

Я также не вижу связи между Bgw и Dialog.

Быстрое решение здесь - не вызывать BeginInvoke внутри цикла, а выполнять всю логику в 1 потоке bgw. Сначала заставь это работать. И совет: настоящие программы не спят ()

И затем, если вы хотите порождать больше потоков, вам необходимо реализовать некоторую логику рандеву. С классом EventWaitHandle или что-то.

Обратите внимание, что это становится намного проще в .NET 4 (с Parallel.ForEach)

0 голосов
/ 22 июля 2011

Установите точку останова на progress.Close(), чтобы увидеть, вызывается ли она (, что приводит к исчезновению окна прогресса ). Вам, вероятно, нужно позвонить DispatcherOperation.Wait(), чтобы убедиться, что DoWork () не завершится, пока вся работа ASYNC не будет полностью завершена. BeginInvoke () возвращает DispatcherOperation - вам нужно использовать его для объединения потоков и ожидания их завершения.

Возможно, вам нужно сохранить список всех вызванных DispatherOperations (pDispatcher.BeginInvoke (update, arg1, arg2, arg3)). После цикла foreach вы просто ждете завершения каждого из них. Я предполагаю, что проблема в том, что RunWorkerCompleted запускается, поскольку вы не ожидаете завершения DispatchOperation (, закрывая, таким образом, окно прогресса ).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...