概述:本指南詳細解釋了在C#中如何在建立控制元件的執行緒以外的執行緒中訪問GUI。基礎功能使用`Control.Invoke`(WinForms)或`Dispatcher.Invoke`(WPF),高階功能則利用`SynchronizationContext`實現執行緒間通訊,確保程式碼清晰可讀。
在C#中,要在建立控制元件的執行緒以外的執行緒訪問控制元件,可以使用Control.Invoke(WinForms)或Dispatcher.Invoke(WPF)。以下是詳細的步驟和示例程式碼,包括基礎功能和高階功能。
在WinForms中訪問控制元件:
基礎功能:
- 建立WinForms應用程式: 建立一個包含按鈕和標籤的WinForms應用程式。
- 使用Invoke訪問控制元件: 在另一個執行緒中使用Control.Invoke訪問控制元件。
示例原始碼:
using System;
using System.Threading;
using System.Windows.Forms;
namespace WinFormsThreadedAccess
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void btnAccessControl_Click(object sender, EventArgs e)
{
// 在另一個執行緒中訪問控制元件
Thread thread = new Thread(AccessControl);
thread.Start();
}
private void AccessControl()
{
if (lblStatus.InvokeRequired)
{
// 在UI執行緒上非同步執行訪問控制元件操作
lblStatus.Invoke(new Action(() => lblStatus.Text = "控制元件已訪問"));
}
else
{
// 在UI執行緒上直接訪問控制元件
lblStatus.Text = "控制元件已訪問";
}
}
}
}
在WPF中訪問控制元件:
基礎功能:
- 建立WPF應用程式: 建立一個包含按鈕和標籤的WPF應用程式。
- 使用Dispatcher訪問控制元件: 在另一個執行緒中使用Dispatcher.Invoke訪問控制元件。
示例原始碼:
using System;
using System.Threading;
using System.Windows;
namespace WPFThreadedAccess
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void btnAccessControl_Click(object sender, RoutedEventArgs e)
{
// 在另一個執行緒中訪問控制元件
Thread thread = new Thread(AccessControl);
thread.Start();
}
private void AccessControl()
{
if (Dispatcher.CheckAccess())
{
// 在UI執行緒上直接訪問控制元件
lblStatus.Content = "控制元件已訪問";
}
else
{
// 在UI執行緒上非同步執行訪問控制元件操作
Dispatcher.Invoke(new Action(() => lblStatus.Content = "控制元件已訪問"));
}
}
}
}
高階功能:
在高階功能中,WinForms和WPF均可以使用SynchronizationContext進行執行緒間通訊,程式碼更為簡潔。
示例原始碼:
using System;
using System.Threading;
using System.Windows.Forms;
namespace AdvancedThreadedAccess
{
public partial class MainForm : Form
{
private readonly SynchronizationContext synchronizationContext;
public MainForm()
{
InitializeComponent();
// 獲取當前同步上下文
synchronizationContext = SynchronizationContext.Current;
}
private void btnAccessControl_Click(object sender, EventArgs e)
{
// 在另一個執行緒中訪問控制元件
Thread thread = new Thread(AccessControl);
thread.Start();
}
private void AccessControl()
{
// 在UI執行緒上非同步執行訪問控制元件操作
synchronizationContext.Post(new SendOrPostCallback(UpdateLabel), "控制元件已訪問");
}
private void UpdateLabel(object state)
{
// 在UI執行緒上更新標籤文字
lblStatus.Text = state.ToString();
}
}
}
在WPF中,Dispatcher本身就是一種同步上下文,所以高階功能的WPF示例程式碼與基礎功能示例程式碼相似。