[ Полезный рекламный блок ]
Попробуйте свои силы в игре, где ваши навыки программирования на C# станут решающим фактором. Переходите по ссылке 🔰.
У C# Windows Forms існує кілька способів оновлення графічного інтерфейсу з іншого потоку. Розглянемо два найпоширеніші підходи.
Використання методу Invoke()
Метод Invoke() дає змогу виконати делегат (метод) у контексті потоку, в якому було створено об’єкт керуючого елемента (control). Для того щоб оновити графічний інтерфейс з іншого потоку, необхідно створити делегат, який міститиме код, що виконує необхідні зміни інтерфейсу, і потім викликати метод Invoke() на об’єкті керуючого елемента, передавши йому створений делегат як параметр:
1 2 3 4 5 6 |
// Running on the worker thread string newText = "abc"; form.Label.Invoke((MethodInvoker)delegate { // Running on the UI thread form.Label.Text = newText; }); |
Розглянемо ще один простий приклад:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
private void button1_Click(object sender, EventArgs e) { RunTask(); } void RunTask() { Task task = Task.Run(() => { for (int i = 0; i < 30; i++) { Thread.Sleep(1000); this.Invoke(new EventHandler(delegate { label1.Text = i.ToString(); })); } } ); } |
Під час натискання на кнопку ‘button1’, відбувається асинхронне циклічне присвоювання інкримінованого значення в ‘label1’, із затримкою в 1 секунду.
Використання методу BeginInvoke()
Метод BeginInvoke() дозволяє виконати делегат асинхронно, тобто не блокуючи головний потік. Цей метод повертає об’єкт типу IAsyncResult, який можна використовувати для перевірки статусу виконання асинхронної операції:
1 2 3 4 5 6 7 8 9 10 11 |
private void UpdateTextBox(string text) { if (textBox1.InvokeRequired) { textBox1.BeginInvoke(new Action<string>(UpdateTextBox), text); } else { textBox1.Text = text; } } |
У цьому прикладі метод UpdateTextBox() викликається з аргументом text. Якщо виклик відбувається з іншого потоку, то метод BeginInvoke() використовується для виконання делегата в контексті потоку, в якому було створено об’єкт керуючого елемента (control). Якщо виклик відбувається з того ж потоку, що й керуючий елемент, то метод виконує безпосередньо код у блоці else.
У метод BeginInvoke() передається делегат, який містить метод UpdateTextBox() і його аргументи. У цьому прикладі використовується лямбда-вираз для створення делегата:
1 2 3 |
textBox1.BeginInvoke((Action)(() => { textBox1.Text = text; })); |
Зверніть увагу, що перед викликом методу BeginInvoke() слід перевірити властивість InvokeRequired у керуючого елемента, щоб переконатися, що виклик відбувається з іншого потоку:
1 2 3 4 5 6 7 8 |
if (textBox1.InvokeRequired) { textBox1.BeginInvoke(new Action<string>(UpdateTextBox), text); } else { textBox1.Text = text; } |
Важливо пам’ятати, що під час використання методу BeginInvoke() слід забезпечити захист доступу до загальних даних, які можуть бути змінені з різних потоків, наприклад, за допомогою блокування (lock).
Я сподіваюся, що вам сподобалося читати цю статтю, і вона виявилася легкою для розуміння. Будь ласка, дайте мені знати, якщо у вас є якісь коментарі або виправлення.
Так само вам може бути цікава попередня стаття – Як зберегти зображення з Picturebox.
Ви хочете навчитися писати код мовою програмування C#?
Створювати різні інформаційні системи, що складаються з сайтів, мобільних клієнтів, десктопних додатків, телеграм-ботів тощо.
Переходьте до нас на сторінку Dijix і ознайомтеся з умовами навчання, ми спеціалізуємося тільки на індивідуальних заняттях, як для початківців, так і для просунутих програмістів. Ви можете взяти як одне заняття для опрацювання питання, що вас цікавить, так і кілька, для більш щільної роботи. Завдяки особистому кабінету, кожен студент підвищить якість свого навчання, у вашому розпорядженні:
- Доступ до пройденого матеріалу
- Тематичні статті
- Бібліотека книг
- Онлайн тестування
- Спілкування в закритих групах