Почему BackgroundWorker_RunWorkerCompleted не обновляет графический интерфейс? - PullRequest
5 голосов
/ 05 января 2010

Я уже искал форум, но ни один из заданных вопросов не подходит к моей проблеме, я думаю ...

Я использую BackgroundWorker для обработки очень трудоемкой операции. После завершения этой операции кнопка должна быть включена, чтобы пользователь мог выполнить другую операцию.

Я использую WPF и следую шаблону MVVM, поэтому у меня нет прямого доступа к этой кнопке. Мне нужно вызвать метод в обработчике события BackgroundWorker_RunWorkerCompleted, который устанавливает свойство, представляющее состояние включенного кнопки, в значение true.

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

Обработчик события BackgroundWorker_RunWorkerCompleted выглядит следующим образом:

    void fileLoadBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
        SetButtonToEnabled(); }

Кто-нибудь знает, как решить эту проблему?

Edit:

Кнопка привязана к команде:

<Button Name="btnLoadTargetFile" Command="{Binding Path=LoadTargetCommand}" .../>

Эта команда является RelayCommand, как сказал Смит в своем блоге (http://msdn.microsoft.com/en-us/magazine/dd419663.aspx), и выглядит так:

public RelayCommand LoadTargetCommand
    {
        get
        {
            if (loadTargetCommand == null)
            {
                loadTargetCommand = new RelayCommand(param => this.OnRequestLoadFile(BusinessLogic.CustomTypes.TreeType.Target), param => this.CanLoadTarget);
            }
            return loadTargetCommand;
        }
        set { loadTargetCommand = value; }
    }

this.CanLoadTarget устанавливается в true с помощью SetButtonToEnabled (); Метод

Редактировать 2:

следующий код 'работает':

fileLoadBackgroundWorker.RunWorkerAsync(argumentList);
while(fileLoadBackgroundWorker.IsBusy)
  System.Windows.Forms.Application.DoEvents();
SetButtonToEnabled();

но это какой-то действительно опасный и уродливый код ...

Ответы [ 2 ]

2 голосов
/ 05 января 2010

Хотя это не объясняет вашу проблему, вы можете попробовать добавить

System.Windows.Forms.Application.DoEvents();

или

Dispatcher.Invoke(new Action(delegate { }), DispatcherPriority.Background);

до конца вызова функции SetButtonToEnabled (после того, как вы установили для кнопки Enabled значение true). Похоже, что фоновый работник вызывает событие Complete, но графический интерфейс не обновляется.

Здесь - полный пример использования Backgroundworker в WPF. Возможно, вы захотите взглянуть на это и убедиться, что ваши вещи выглядят одинаково.

Вы также можете взглянуть на Асинхронная многопоточность с фоновым рабочим объектом . Это хороший пример использования Dispatcher и Backgroundworker

Модель потоков WPF - еще один замечательный источник для проверки.

1 голос
/ 05 января 2010

Ваша проблема, вероятно, не имеет ничего общего с BackgroundWorker. Если вы вызываете метод SetButtonToEnabled непосредственно из основного потока, вы, вероятно, увидите такое же поведение. Для проверки этого замените вызов на RunWorkerAsync одним на SetButtonToEnabled.

Несколько комментаторов предложили вам взглянуть на реализацию INotifyPropertyChanged, это звучит как хороший совет.

...