首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

WinForms 類別呼叫表單後台方法:委派、介面與靜態實例三種模式

     編輯:關於.NET

問題

在非表單類別 (如網路監聽、背景執行緒) 中需要更新 UI 控制項 (ListView、TextBox 等),但無法直接存取表單實例的控制項 (非 public) 或方法。

模式一:委派回調 (推薦)

表單定義委派與事件

public partial class MainForm : Form
{
    public event Action<string> OnMessageReceived;

    public MainForm() { InitializeComponent(); }

    private void AppendLog(string msg)
    {
        if (listView1.InvokeRequired)
            listView1.Invoke(new Action<string>(AppendLog), msg);
        else
            listView1.Items.Add(msg);
    }

    // 供外部呼叫的 public 方法
    public void ReceiveMessage(string msg) => AppendLog(msg);
}

外部類別訂閱/呼叫

public class NetworkListener
{
    private MainForm _form;
    public NetworkListener(MainForm form) { _form = form; }

    public void OnDataReceived(string data)
    {
        // 方式 A: 直接呼叫 public 方法 (需確保執行緒安全)
        _form.ReceiveMessage(data);

        // 方式 B: 觸發事件 (表單自行處理 Invoke)
        _form.OnMessageReceived?.Invoke(data);
    }
}

模式二:介面解耦 (單元測試友善)

public interface ILogView
{
    void AppendLog(string message);
}

public partial class MainForm : Form, ILogView
{
    public void AppendLog(string message) { /* Invoke 實作 */ }
}

public class NetworkListener
{
    private ILogView _view;
    public NetworkListener(ILogView view) { _view = view; }
    public void OnDataReceived(string data) => _view.AppendLog(data);
}

模式三:靜態實例 (快速原型、不推薦生產)

public partial class MainForm : Form
{
    public static MainForm Instance { get; private set; }
    public MainForm() { InitializeComponent(); Instance = this; }
}

// 任意處呼叫
MainForm.Instance?.ReceiveMessage("msg");
缺點:強耦合、難測試、多實例場景失效、記憶體洩漏風險。

執行緒安全鐵律

所有跨執行緒 UI 操作必須透過 Control.Invoke 或 BeginInvoke 執行於 UI 執行緒:

if (control.InvokeRequired)
    control.Invoke((MethodInvoker)delegate { /* UI 操作 */ });
else
    /* UI 操作 */;

最佳實踐建議

  1. 優先使用 介面 + 依賴注入,表單實作介面,外部類別依賴介面而非具體類別。
  2. 表單內封裝 Invoke 邏輯,對外暴露執行緒安全的 public 方法。
  3. 避免將控制項設為 public/static,破壞封裝。
  4. 背景工作考慮使用 BackgroundWorker、Task.Run + Progress<T>、SynchronizationContext。

圖示說明

類別呼叫表單方法示意

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved