У меня есть ProgressBarWindow, который имеет progressbar и кнопку отмены на нем, которую я использую для создания отчетов о достижениях по файловому вводу-выводу. Однако Поток UI ProgressBarWindow и моего главного окна оба зависает несмотря на всю работу, сделанную в backgroundworker. progressbar представляется, как мое главное окно, но не обновляет, пока backgroundworker делает свою вещь. Следующий код называют в самом конце конструктора главного окна:
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 (остальное - просто несколько методов set):
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;
}
}
}
Я попытался перенести строку метода set значения в делегата dispatcher.invoke, но это дает мне переполнение стека (у меня не придется быть dispatcher.invoke строки так или иначе, как backgroundworker называет ProgressChanged в Потоке UI, правильно?). Я проверил MSDN и погуглил, но я, может казаться, не нахожу никого больше с этой проблемой.
Извинения РЕДАКТИРОВАНИЯ, я не понял, что мой упрощенный код заблокировал Поток UI, я получаю точно то же поведение несмотря на использование backgroundworker, таким образом, я ошибочно предположил, что они были эквивалентны. Я должен был упомянуть, что использовал backgroundworker :P
Вы блокируете поток пользовательского интерфейса, поэтому он не будет повторно отображать пользовательский интерфейс до тех пор, пока ваш цикл завершен.
Переместите фоновую обработку в отдельный поток и используйте соответствующие вызовы Dispatcher
(или BackgroundWorker
), чтобы маршалировать вызовы обновления пользовательского интерфейса обратно в поток пользовательского интерфейса.
Если ваш индикатор выполнения на самом деле предназначен только для использования в качестве таймера, вы можете использовать один из классов Timer
для его обновления.
РЕДАКТИРОВАТЬ: Хорошо, теперь вы изменили код, мне он кажется нормальным. Он должен быть потокобезопасным, поскольку вы изменяете пользовательский интерфейс только в потоке пользовательского интерфейса. Ваш фоновый работник определенно периодически сообщает о прогрессе?
Послушайте Джона Скита, или вы можете иногда вызывать Application.DoEvents (), чтобы все обновления пользовательского интерфейса выполнялись в одном потоке.