c # ProgressBar не обновляется - PullRequest
8 голосов
/ 02 августа 2010

У меня есть ProgressBarWindow, в котором есть индикатор выполнения и кнопка отмены, которую я использую, чтобы сообщить о прогрессе файлового ввода-вывода.Тем не менее, поток пользовательского интерфейса в ProgressBarWindow и мое главное окно зависают, несмотря на всю работу, выполняемую в фоновом режиме.Индикатор выполнения отображается, как и мое главное окно, но не обновляется, пока фоновый работник делает свое дело.Следующий код вызывается в самом конце конструктора главного окна:

iCountLogLinesProgressBar = new ProgressBarWindow();
iCountLogLinesProgressBar.cancelButton.Click += EventCountLogLinesProgressBarCancelButtonClicked;
iCountLogLinesProgressBar.Show();

iCountLogRecords = new BackgroundWorker();
iCountLogRecords.DoWork += EventCountLogLinesDoWork;
iCountLogRecords.ProgressChanged += EventCountLogLinesProgressChanged;
iCountLogRecords.RunWorkerCompleted += EventCountLogLinesRunWorkerCompleted;
iCountLogRecords.WorkerReportsProgress = true;
iCountLogRecords.WorkerSupportsCancellation = true;
iCountLogRecords.RunWorkerAsync(new BinaryReader(File.Open(iMainLogFilename, FileMode.Open, FileAccess.Read)));

EventCountLogLinesProgressChanged () выглядит так:

private void EventCountLogLinesProgressChanged(object sender, ProgressChangedEventArgs e)
{
    iCountLogLinesProgressBar.Value = e.ProgressPercentage;
}

Вот сокращенная версия ProgressBarWindow (остальное - только пара установщиков):

public partial class ProgressBarWindow : Window
{
    public ProgressBarWindow()
    {
        InitializeComponent();
        this.progressBar.Value = this.progressBar.Minimum = 0;
        this.progressBar.Maximum = 100;
    }

    public double Value
    {
        get
        {
            return progressBar.Value;
        }
        set
        {
            this.progressBar.Value = value;
        }
    }
} 

Я попытался обернуть строку установщика значений в делегат dispatcher.invoke, но это дает мне переполнение стека (мне не нужно было иметьВ любом случае, dispatcher.invoke вызывает строку, поскольку фоновый работник вызывает ProgressChanged в потоке пользовательского интерфейса, верно?).Я проверил MSDN и Google, но я не могу найти никого другого с этой проблемой.

РЕДАКТИРОВАТЬ Извините, я не понял, что мой упрощенный код заблокировал поток пользовательского интерфейса, я получаю точно такое же поведение, несмотря на использование фонового работника, поэтому я ошибочно предположил, что они эквивалентны.Я должен был упомянуть, что использовал фонового работника: P

Ответы [ 2 ]

15 голосов
/ 02 августа 2010

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

Переместите фоновую обработку в отдельный поток и используйте соответствующие вызовы Dispatcher (или BackgroundWorker) для маршалирования обновлений пользовательского интерфейса обращаются обратно к потоку пользовательского интерфейса.

Если ваш индикатор выполнения действительно просто предназначен для таймера, вы можете использовать один из Timerклассы для его обновления.

РЕДАКТИРОВАТЬ: Хорошо, теперь вы изменили код, мне кажется, все в порядке.Это должно быть поточно-ориентированным, так как вы изменяете пользовательский интерфейс только в потоке пользовательского интерфейса.Ваш опытный работник периодически сообщает о прогрессе?

3 голосов
/ 02 августа 2010

Послушай Джона Скита, или вы можете иногда вызывать Application.DoEvents () для выполнения всех обновлений пользовательского интерфейса в одном потоке.

...