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

WinForm 窗體間數據傳遞交互四大模式:從強耦合到事件解耦的演進之路

     編輯:ASP.NET 基礎

場景描述

主窗體開啟子窗體,子窗體需向主窗體傳遞數據(如修改標題、提交表單數據)。本文梳理四種模式,由淺入深展示耦合度降低過程。

模式一:構造函數傳遞主窗體引用(強耦合)

// 主窗體
var child = new ChildForm(this);
child.Show();

// 子窗體
public class ChildForm : Form {
    private MainForm _main;
    public ChildForm(MainForm main) { _main = main; }
    
    private void btnOK_Click(object sender, EventArgs e) {
        _main.txtTitle.Text = this.txtInput.Text; // 直接操作主窗體控件
    }
}

缺點: 子窗體依賴具體主窗體類型,暴露所有 public 成員,違反迪米特法則,難以複用與測試。

模式二:介面隔離(契約耦合)

// 定義契約
public interface ITitleChanger {
    void ChangeTitle(string title);
}

// 主窗體實現介面
public class MainForm : Form, ITitleChanger {
    public void ChangeTitle(string title) { this.Text = title; }
    
    private void btnOpen_Click(object sender, EventArgs e) {
        var child = new ChildForm(this); // this 作為 ITitleChanger 傳遞
        child.Show();
    }
}

// 子窗體依賴介面
public class ChildForm : Form {
    private ITitleChanger _changer;
    public ChildForm(ITitleChanger changer) { _changer = changer; }
    
    private void btnOK_Click(object sender, EventArgs e) {
        _changer.ChangeTitle(this.txtInput.Text); // 僅調用契約方法
    }
}

優點: 子窗體僅知曉「能改標題」,不知曉具體實現,降低耦合,便於單元測試(Mock 介面)。

模式三:委托回調(輕量級回調)

// 子窗體定義委托
public partial class ChildForm : Form {
    public delegate void TitleChangedHandler(string title);
    public event TitleChangedHandler TitleChanged;
    
    private void btnOK_Click(object sender, EventArgs e) {
        TitleChanged?.Invoke("New Title"); // 觸發委托
    }
}

// 主窗體訂閱委托
public partial class MainForm : Form {
    private ChildForm _child = new ChildForm();
    
    public MainForm() {
        InitializeComponent();
        _child.TitleChanged += OnChildTitleChanged; // 註冊處理器
    }
    
    private void OnChildTitleChanged(string title) {
        this.Text = title;
    }
    
    private void btnOpen_Click(object sender, EventArgs e) {
        _child.Show();
    }
}

特點: 無需定義介面,語法簡潔,適合單一回調場景。委托本質是類型安全的函數指針。

模式四:自定義事件 + EventArgs(標準事件模式,最推薦)

// 子窗體:完整事件模式
public partial class ChildForm : Form {
    // 1. 事件參數類,攜帶業務數據
    public class UserAddedEventArgs : EventArgs {
        public User User { get; set; }
        public UserAddedEventArgs(User user) { User = user; }
    }
    
    // 2. 事件聲明
    public event EventHandler<UserAddedEventArgs> UserAdded;
    
    // 3. 觸發方法
    protected virtual void OnUserAdded(UserAddedEventArgs e) {
        UserAdded?.Invoke(this, e);
    }
    
    // 4. 業務邏輯中觸發
    private void btnAdd_Click(object sender, EventArgs e) {
        var user = new User { Name = txtName.Text, Password = txtPwd.Text };
        OnUserAdded(new UserAddedEventArgs(user));
    }
}

// 主窗體:訂閱並處理
public partial class MainForm : Form {
    private void btnOpenUserDialog_Click(object sender, EventArgs e) {
        using (var dialog = new ChildForm()) {
            dialog.UserAdded += OnUserAdded; // 訂閱
            dialog.ShowDialog();
        }
    }
    
    private void OnUserAdded(object sender, ChildForm.UserAddedEventArgs e) {
        MessageBox.Show($"新用戶:{e.User.Name}");
        // 刷新列表、保存數據庫等
    }
}

模式對比總結

模式耦合度適用場景優點缺點
構造函數傳引用極高極簡單、一次性對話框代碼最少強依賴具體類、難測試、不可複用
介面隔離中等多種實現、需單元測試契約清晰、可 Mock需定義介面、稍顯繁瑣
委托回調低單一回調、簡單數據傳遞語法簡潔、無額外類型多播委托易誤用、不攜帶豐富上下文
自定義事件最低標準元件、複雜數據、多訂閱者符合 .NET 規範、支援 EventArgs、可多播代碼量最大

核心設計原則

「子窗體只負責『引發事件』,不關心『如何處理』——這是鬆耦合的本質。」

  • 單一職責: 子窗體專注 UI 交互與數據收集
  • 依賴倒置: 依賴抽象(介面/委托/事件)而非具體實現
  • 開放封閉: 新增處理邏輯無需修改子窗體代碼

進階技巧:非模態窗體的數據同步

// 子窗體暴露公共屬性/方法供主窗體主動拉取
public User CurrentUser { get; private set; }

// 主窗體定時器或事件中拉取
private void timer_Tick(object sender, EventArgs e) {
    if (child.CurrentUser != null) {
        UpdateUI(child.CurrentUser);
    }
}

或結合 INotifyPropertyChanged 實現雙向綁定。

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