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

C# WinForms 父子視窗控制項互操作:兩種傳遞父視窗參考的模式

     編輯:關於C語言

前言

WinForms 開發常遇到子視窗需操作父視窗控制項、或父視窗操作子視窗控制項的需求。本文介紹兩種核心模式讓子視窗取得父視窗參考,並強調以公用屬性/方法封裝控制項操作,而非直接暴露控制項公開欄位。

模式一:父視窗靜態單例參考

適用於應用程式僅有一個主視窗實例的情境(典型 MDI 或單視窗應用)。

父視窗實作


public partial class MainForm : Form
{
    // 靜態屬性保存當前實例
    public static MainForm CurrentInstance { get; private set; }
    
    public MainForm()
    {
        InitializeComponent();
        CurrentInstance = this;  // 建構子中指派
    }
    
    // 封裝控制項操作為公用方法/屬性
    public string StatusText
    {
        get => lblStatus.Text;
        set => lblStatus.Text = value;
    }
    
    public void RefreshDataGrid()
    {
        dataGridView1.DataSource = GetLatestData();
    }
}

子視窗使用


public partial class ChildForm : Form
{
    public ChildForm()
    {
        InitializeComponent();
    }
    
    private void btnUpdateParent_Click(object sender, EventArgs e)
    {
        // 直接透過靜態屬性存取父視窗
        if (MainForm.CurrentInstance != null)
        {
            MainForm.CurrentInstance.StatusText = "子視窗更新於 " + DateTime.Now;
            MainForm.CurrentInstance.RefreshDataGrid();
        }
    }
}

模式二:建構子注入父視窗參考

適用於多主視窗、多子視窗、或需明確父子關係的情境。更符合依賴注入原則,易於單元測試。

子視窗實作


public partial class ChildForm : Form
{
    private readonly MainForm _parentForm;
    
    // 建構子要求傳入父視窗
    public ChildForm(MainForm parentForm)
    {
        InitializeComponent();
        _parentForm = parentForm ?? throw new ArgumentNullException(nameof(parentForm));
    }
    
    private void btnNotifyParent_Click(object sender, EventArgs e)
    {
        _parentForm.StatusText = $"子視窗 {this.Text} 通知於 {DateTime.Now}";
        _parentForm.RefreshDataGrid();
    }
}

父視窗建立子視窗


public partial class MainForm : Form
{
    private void btnOpenChild_Click(object sender, EventArgs e)
    {
        // 傳入 this 給子視窗建構子
        var child = new ChildForm(this);
        child.Show();  // 或 ShowDialog()
    }
}

核心原則:封裝控制項操作

❌ 反模式:直接暴露控制項

// 父視窗
public Button btnSave;  // 破壞封裝,子視窗可任意修改任何屬性

// 子視窗
parent.btnSave.Visible = false;
parent.btnSave.Text = "Hacked!";
parent.btnSave.Click += MaliciousHandler();
✅ 正確模式:公開語意化屬性/方法

// 父視窗
public bool CanSave 
{ 
    get => btnSave.Enabled; 
    set => btnSave.Enabled = value; 
}

public void TriggerSave() => btnSave.PerformClick();

// 子視窗
parent.CanSave = false;           // 語意清晰
parent.TriggerSave();             // 行為明確

兩種模式比較

維度靜態單例建構子注入
適用場景單一主視窗、全域存取點多視窗、明確父子關係、可測試性
耦合度高(子視窗依賴具體父視窗類別)中(可抽象介面降低耦合)
生命週期父視窗存活期間全域可用隨子視窗實例建立/銷毀
執行緒安全需注意跨執行緒存取同樣需注意
單元測試難以模擬易於注入 Mock 父視窗

進階:定義介面降低耦合


// 定義父視窗契約
public interface IParentForm
{
    string StatusText { get; set; }
    void RefreshDataGrid();
    event Action DataRefreshed;
}

// 父視窗實作介面
public partial class MainForm : Form, IParentForm { ... }

// 子視窗依賴介面而非具體類別
public partial class ChildForm : Form
{
    private readonly IParentForm _parent;
    public ChildForm(IParentForm parent) { _parent = parent; }
}

總結

父子視窗互操作核心在於如何取得參考(靜態單例 vs 建構子注入)與如何封裝操作(公開語意化屬性/方法 vs 暴露控制項)。建議優先採用建構子注入 + 介面契約 + 封裝操作,兼顧架構清晰、可測試性與封裝性。

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