вторник, 21 мая 2013 г.

Багатопотоковість в WPF. Dispatcher.

Під багатопотоковістю (Multithreading) розуміється виконання одночасно більше одного блоку коду. Зазвичай  багатопотоковість використовується для створення більш гнучкого користувальницького інтерфейсу (UI) . Наприклад,  виконання завдань, які займають багато часу в іншому потоці (завантаження файлу), що дозволяє залишити користувацький інтерфейс (UI) доступним для введення даних .




WPF підтримує a Single Threaded Apartment Model (STA), яка вводить такі обмеження у  WPF апплікації.
  1. Потік, який створює елементи користувацького інтерфейсу WPF володіє цими  елементами та інші потоки, не можуть взаємодіяти  безпосередньо з елементами користувацького  інтерфейсу.  Це відомо як спорідненність потоків ( thread affinity).
  2. WPF об'єкти, які мають спорідненність потоків ( thread affinity) наслідуються від класу DispatcherObject в якійсь точці їх ієрархії класів.
На практиці один потік виконує всю апплікацію і володіє об'єктами WPF.

The Dispatcher
Диспетчер управляє роботою, яка відбувається в WPF апплікації. Диспетчер володіє потоком апплікації і отже, всіма об'єктами, які належать до потоку.  Під час роботи апплікації диспетчер приймає нові запити роботи і виконує їх по одному.
Формально диспетчер створюється при початковому створенні в новому потоці екземпляра класу, який наслідується від DispatcherObject . У випадку створеня окремих потоків і використання їх для відображення окремих вікон получається більше одного диспетчера. В більшості апплікації не ускладнюється ситуація і обходиться одним потоком  користувацького інтерфейсу і одним диспетчером. Потім використовується багатопотоковість для управління операціями з данними  і іншими фоновими задачами.
The DispatcherObject  включає метод  VerifyAccess,  який  викликає InvalidOperationException екзепшн, якщо інший потік намагається доступити до  обєкту апплікації.
Приклад: 
В  даному прикладі намагатимемось змінити значення проперті Text текстбокса з нового  потоку.
   1: #region Wrong implementation

   2:  

   3:  private void Button_Click_UpdateTextWrong(object sender, RoutedEventArgs e)

   4:  {

   5:      Thread thr = new Thread(UpdateWrong);

   6:      thr.Start();

   7:  }

   8:  

   9:  private void UpdateWrong(object obj)

  10:  {

  11:      Thread.Sleep(1000);

  12:      this.TextBox_UpdateWrong.Text = "Here is some new text";

  13:  }

  14:  

  15:  #endregion

В даному випадку викличеться екзепшн, оскільки новий потік  не буде мати доступу до WPF елементу – текстбокс.

error

Для вирішення цієї проблеми можна використати Диспетчер


   1: #region Better implementation

   2:  

   3:  private void Button_Click_UpdateTextBetter(object sender, RoutedEventArgs e)

   4:  {

   5:      Thread thr = new Thread(UpdateBetter);

   6:      thr.Start();

   7:  }

   8:  

   9:  private void UpdateBetter(object obj)

  10:  {

  11:      Thread.Sleep(10000);

  12:  

  13:      this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,

  14:          (ThreadStart)( ()=> { this.TextBox_UpdateBetter.Text = "New text"; } ));

  15:      

  16:  }

  17:  

  18:  #endregion

Метод  Dispatcher.BeginInvoke() приймає 2 параметри. Перший вказує пріоритет завдання. Другий параметр являється делегатом, який вказує на метод з кодом, який ви хочете виконати.

Скачати приклад

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

Отправить комментарий