BackgroundWorker: включение / отключение кнопок в завершенном событии не работает после переключения между пользовательскими элементами управления - PullRequest
1 голос
/ 08 октября 2010

У меня проблема с моим BackgroundWorker, помещенным в UserControl. Мое приложение WPF имеет навигацию слева, и каждая запись загружает свой собственный UserControl, где пользователь может создать файл PDF.

Поскольку создание PDF занимает некоторое время, я реализовал BackgroundWorker, который выполняет эту работу, и дополнительно я отключаю некоторые кнопки и показываю индикатор выполнения. В событии RunWorkerCompleted я сбрасываю состояние кнопок и скрываю индикатор выполнения.

Все это работает очень хорошо, несмотря на один сценарий: Во время создания PDF-файла пользователь может переключаться между пользовательскими элементами управления и, если он возвращается к элементу управления, с которого он начал задание, элемент управления должен отображать индикатор выполнения и кнопки как отключенные. Чтобы достичь этого, я добавил переменную (isProcessing) в UserControl.

А конструктор управления у меня такой:

        // Check if a current process is running, if so: handle button/progressbar visibility
        if (_isProcessing)
        {
            _stkProgressBar.Visibility = Visibility.Visible;
            progressBar1.IsIndeterminate = true;

            // Disabling the buttons here is just working with a hack in
            // the "Button_IsEnabledChanged" event.
            btnDaten.IsEnabled = false;
            btnBericht.IsEnabled = false;
            this.Cursor = Cursors.Wait;
        }
        else
        {
            _stkProgressBar.Visibility = Visibility.Hidden;
        }

Включение / отключение кнопок там просто работает из-за этого грязного хака:

    private void btnDaten_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        //HACK: We want to disable the report buttons if a report execution is running.
        //      Disabling the buttons in the Load Event of the control isn't working
        if (_isProcessing && (bool)e.NewValue)
        {
            btnDaten.IsEnabled = false;
            btnBericht.IsEnabled = false;
        }
    }

Теперь, если задание выполняется и пользователь переключается между элементами управления, состояние элемента управления обработки в порядке. Но если задание завершено и PDF готов, кнопки не могут быть включены, а индикатор выполнения также остается видимым. Код помещается в событие RunWorkerCompleted:

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        // This is not working if the user switches between the controls
        _isProcessing = false;
        this.Cursor = Cursors.Arrow;
        _stkProgressBar.Visibility = Visibility.Hidden;
        btnDaten.IsEnabled = true;
        btnBericht.IsEnabled = true;
    }

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

1 Ответ

3 голосов
/ 08 октября 2010

Да, проблема заключается в переключении между пользовательскими элементами управления.Когда вы выключаете и переключаетесь обратно, вы создаете новый экземпляр элемента управления.Который создает новый экземпляр BackgroundWorker.У которого есть обработчик события RunWorkerCompleted, который не связан с BGW, который на самом деле работает.

В вашем коде есть другая ошибка, это должно привести к аварийному завершению вашей программы с ObjectDisposedException, когда исходный экземпляр BGW завершает работу и устанавливает(теперь невидимые) свойства управления.Вы забываете вызывать Dispose () для пользовательских элементов управления, когда вы переключаетесь между ними.Не совсем уверен, как это сделать в WPF, но в winforms это непоправимая утечка.

Вам придется делать это по-другому, если вы хотите поддерживать переключение.Экземпляр BGW должен быть отделен от экземпляра пользовательского элемента управления, чтобы он мог пережить коммутатор.Довольно болезненно, вам придется связывать и связывать события, когда элемент управления создается и удаляется, вам обязательно нужно переопределить метод Dispose () и не забывать вызывать его.Делать BGW статическим можно оправданно, если вы разрешаете выполнять только одно задание.Который должен быть нормальным.Укладка пользовательских элементов управления таким образом, чтобы вы их когда-либо создавали только один раз, является исправлением для вопросов и ответов.

...