掌握C#中的GUI多執行緒技巧:WinForms和WPF例項詳解

架构师老卢發表於2024-03-19
掌握C#中的GUI多執行緒技巧:WinForms和WPF例項詳解

概述:本指南詳細解釋了在C#中如何在建立控制元件的執行緒以外的執行緒中訪問GUI。基礎功能使用`Control.Invoke`(WinForms)或`Dispatcher.Invoke`(WPF),高階功能則利用`SynchronizationContext`實現執行緒間通訊,確保程式碼清晰可讀。

在C#中,要在建立控制元件的執行緒以外的執行緒訪問控制元件,可以使用Control.Invoke(WinForms)或Dispatcher.Invoke(WPF)。以下是詳細的步驟和示例程式碼,包括基礎功能和高階功能。

在WinForms中訪問控制元件:

基礎功能:

  1. 建立WinForms應用程式: 建立一個包含按鈕和標籤的WinForms應用程式。
  2. 使用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中訪問控制元件:

基礎功能:

  1. 建立WPF應用程式: 建立一個包含按鈕和標籤的WPF應用程式。
  2. 使用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示例程式碼與基礎功能示例程式碼相似。

相關文章