Pull to refresh

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

Около года назад я познакомился с технологией 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. Надеюсь данная статья кому-то будет полезна.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.