Отмена рабочих потоков в winforms - PullRequest
4 голосов
/ 18 июня 2009

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

Я использовал потоки BackgroundWorker для заполнения.

bw_LoadAll.DoWork += new DoWorkEventHandler(bg_LoadAllWork);
bw_LoadAll.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bg_LoadAllWorkCompleted);
bw_LoadAll.WorkerSupportsCancellation = true;

Я подписался на событие SelectedIndexChanged для мастера и установил отмененное значение равным true:

bw_LoadAll.CancelAsync();

Вот код в методе DoWork:

List<object> s = Repository.Instance().LoadAll();
if (!bw_LoadAll.CancellationPending) {
    e.Result = s;
} else {
    e.Cancel = true;
}

Но по какой-то причине код для завершенного работника продолжает вызываться. Вот рабочий код:

if (!e.Cancelled) {
    ddl.DataSource = e.Result;
    ddl.DisplayMember = "QuickName";
    ddl.ValueMember = "ID";
}

Есть ли что-то еще, что я должен сделать, чтобы отменить эту тему от возвращения?

Ответы [ 3 ]

5 голосов
/ 18 июня 2009

Ваш метод, bg_LoadAllWork, должен быть определен как:

void bg_LoadAllWork(object sender, DoWorkEventArgs e)
{
    // Do your work here...
} 

Внутри bg_LoadAllWork вам нужно проверить на e.CancellationPending, и если это правда, установить e.Cancel = true;

Эта последняя часть важна - если вы никогда не устанавливали e.Cancel, то ваш e.Cancelled никогда не будет равен true. Вызов CancelAsync на самом деле ничего не отменяет - это больше похоже на «Запрос на отмену фоновой работы» - вы должны установить логику, чтобы вызвать отмену.

0 голосов
/ 18 июня 2009

Прошло довольно много времени с тех пор, как я использовал BackgroundWorker, но если я выполняю память, когда вы вызываете bw_LoadAll.CancelAsync, нет фактического прерывания вашего LoadAllWork метода, если только LoadAllWork не проверяет bw_LoadAll.CancelationPending.

Подтверждено http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.cancelasync.aspx: "CancelAsync отправляет запрос на завершение ожидающей фоновой операции и устанавливает для свойства CancellationPending значение true.

Когда вы вызываете CancelAsync, ваш рабочий метод имеет возможность остановить его выполнение и выйти. Рабочий код должен периодически проверять свойство CancellationPending, чтобы убедиться, что для него установлено значение true. "

Итак, в вашем обработчике событий SelectedIndexChanged, когда вы вызываете bw_LoadAll.CancelAsync(), он устанавливает bw_LoadAll.CancelationPending в true, но фактически не прерывает метод LoadAllWork. Медленный загрузчик все еще заканчивает работу.

0 голосов
/ 18 июня 2009

С CodeProject в вашей функции do_work вы должны проверить CancellationPending в рабочем потоке, а затем установить для переменной DoWorkEventArgs.Cancel значение true.

...