WPF підтримує a Single Threaded Apartment Model (STA), яка вводить такі обмеження у WPF апплікації.
- Потік, який створює елементи користувацького інтерфейсу WPF володіє цими елементами та інші потоки, не можуть взаємодіяти безпосередньо з елементами користувацького інтерфейсу. Це відомо як спорідненність потоків ( thread affinity).
- WPF об'єкти, які мають спорідненність потоків ( thread affinity) наслідуються від класу DispatcherObject в якійсь точці їх ієрархії класів.
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 елементу – текстбокс.
Для вирішення цієї проблеми можна використати Диспетчер
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 параметри. Перший вказує пріоритет завдання. Другий параметр являється делегатом, який вказує на метод з кодом, який ви хочете виконати.
Скачати приклад
Комментариев нет:
Отправить комментарий