Особенности использования ProgressBar в WPF

11 Дек
2011

Около года назад я познакомился с технологией WPF. При освоении, как обычно, возникали различные трудности.
Однажды собрался я написать для собственных нужд синхронизатор на C#. Захотелось использовать WPF. Все продвигалось хорошо, пока я не решил добавить ProgressBar. До этого был опыт использования Window Forms, где для демонстрации прогресса достаточно было в цикле увеличивать свойство Value. По привычке также было сделано и здесь. Но, оказалось, не все так просто.
При выполнении длительной операции (в моем случае — это копирование файлов), обновление ProgressBar происходило только при освобождении потока выполнения, т.е. после завершения операции. При таком поведении данный элемент управления абсолютно бесполезен. Поиск по MSDN ничем не увенчался. На помощь пришел гугл.

На stackoverflow было найдено следующее решение:
  1. Объявить глобальный тип делегат
  2. Создать делегат
  3. Привязать его к изменению Dependency property элемента

//Объявление типа делегата
delegate void UpdateProgressBarDelegate(DependencyProperty dp, object value);

//Создание делегата и привязка к изменению свойства
UpdateProgressBarDelegate updProgress = new UpdateProgressBarDelegate(progressBar.SetValue);

//Изменения прогресса
Dispatcher.Invoke(updProgress, new object[] { ProgressBar.ValueProperty, ++value });        


Для отзывчивости интерфейса длительные операции необходимо проводить в фоновом потоке. Для этих целей хорошо подходит BackgroundWorker. Таким образом получаем следующее решение:

delegate void UpdateProgressBarDelegate(DependencyProperty dp, object value);
public partial class MainWindow : Window
{
    BackgroundWorker worker;

    public MainWindow()
    {
        worker = new BackgroundWorker();
        worker.DoWork += new DoWorkEventHandler(worker_DoWork);       
     }

     void worker_DoWork(object sender, DoWorkEventArgs e)
     {
         CopyFiles();
     }
        
     private void CopyFiles()
     {
         UpdateProgressBarDelegate updProgress = new UpdateProgressBarDelegate(progressBar.SetValue);
         double value = 0;
         foreach (string item in FilesToCopy)
         {
             File.Copy(item, OutputFolderName);
             Dispatcher.Invoke(updProgress, new object[] { ProgressBar.ValueProperty, ++value });
         }                        
     }

     private void RunButton_Click(object sender, RoutedEventArgs e)
     {
         progressBar.Maximum = FilesToCopy.Count;                         
         progressBar.Value = 0;
         worker.RunWorkerAsync();
     }


Детали реализации опущены.

Вот таким способом необходимо использовать ProgressBar в WPF. Надеюсь данная статья кому-то будет полезна.
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх