In user interface (UI) applications such as WPF (Windows Presentation Foundation) and WinForms, thread management is essential because UI elements can only be updated from the UI thread.
Any attempt to update the UI from a background thread will result in an exception.
When using threading techniques such as Thread
, ThreadPool
, Task
, or async/await
, it is important to marshal UI updates to the UI thread.
Below, we’ll explore how to update the UI in WPF and WinForms using different threading techniques.
WPF - Updating the UI
In WPF, the UI thread is the main thread that manages UI updates.
To update UI elements from a background thread, you need to use the Dispatcher
to marshal the call back to the UI thread.
1. Using Thread
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| public void StartBackgroundTask()
{
Thread backgroundThread = new Thread(() =>
{
// Simulate long-running task
Thread.Sleep(2000);
// Update the UI from the UI thread using Dispatcher
Dispatcher.Invoke(() =>
{
myLabel.Content = "Task Completed"; // Update UI element
});
});
backgroundThread.Start();
}
|
2. Using ThreadPool
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| public void StartBackgroundTask()
{
ThreadPool.QueueUserWorkItem(state =>
{
// Simulate long-running task
Thread.Sleep(2000);
// Update the UI from the UI thread using Dispatcher
Dispatcher.Invoke(() =>
{
myLabel.Content = "Task Completed";
});
});
}
|
3. Using Task
(Task.Run)
1
2
3
4
5
6
7
8
9
10
11
| public async Task StartBackgroundTaskAsync()
{
await Task.Run(() =>
{
// Simulate long-running task
Thread.Sleep(2000);
});
// Update the UI from the UI thread
myLabel.Content = "Task Completed";
}
|
4. Using async/await
1
2
3
4
5
6
7
| public async Task StartBackgroundTaskAsync()
{
await Task.Delay(2000); // Simulate an async I/O-bound task
// This update happens on the UI thread automatically after awaiting
myLabel.Content = "Task Completed";
}
|
In WinForms, similar to WPF, UI elements can only be updated from the main UI thread.
You can use the Invoke
method to marshal the update from a background thread to the UI thread.
1. Using Thread
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| public void StartBackgroundTask()
{
Thread backgroundThread = new Thread(() =>
{
// Simulate long-running task
Thread.Sleep(2000);
// Update UI from the UI thread using Invoke
myLabel.Invoke((Action)(() =>
{
myLabel.Text = "Task Completed"; // Update UI element
}));
});
backgroundThread.Start();
}
|
2. Using ThreadPool
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| public void StartBackgroundTask()
{
ThreadPool.QueueUserWorkItem(state =>
{
// Simulate long-running task
Thread.Sleep(2000);
// Update UI from the UI thread using Invoke
myLabel.Invoke((Action)(() =>
{
myLabel.Text = "Task Completed";
}));
});
}
|
3. Using Task
(Task.Run)
1
2
3
4
5
6
7
8
9
10
11
| public async Task StartBackgroundTaskAsync()
{
await Task.Run(() =>
{
// Simulate long-running task
Thread.Sleep(2000);
});
// Update UI from UI thread
myLabel.Text = "Task Completed";
}
|
4. Using async/await
1
2
3
4
5
6
7
| public async Task StartBackgroundTaskAsync()
{
await Task.Delay(2000); // Simulate an async I/O-bound task
// This update happens on the UI thread after the await completes
myLabel.Text = "Task Completed";
}
|
Reference Links