在 WinForms 中实现子窗口向父窗口传值,可以通过多种方式实现。以下是 5 种常用方法及其详细步骤和示例代码,涵盖不同场景需求:
方法 1:通过公共属性(适合模态窗口)
场景:子窗口是模态窗口(ShowDialog()),父窗口等待子窗口关闭后直接获取值。
步骤:
子窗口定义公共属性:
public partial class ChildForm : Form
{
public string ReturnValue { get; private set; } // 父窗口可读取的属性
private void btnOK_Click(object sender, EventArgs e)
{
ReturnValue = txtInput.Text;
this.DialogResult = DialogResult.OK; // 关闭窗口
}
}
父窗口调用并获取值:
private void btnOpenChild_Click(object sender, EventArgs e)
{
using (var childForm = new ChildForm())
{
if (childForm.ShowDialog() == DialogResult.OK)
{
string value = childForm.ReturnValue;
lblResult.Text = $"接收的值:{value}";
}
}
}
方法 2:通过事件(适合非模态窗口)
场景:子窗口是非模态窗口(Show()),父窗口需要实时接收数据。
步骤:
子窗口定义事件:
public partial class ChildForm : Form
{
// 定义事件委托
public event Action<string> DataPassed;
private void btnSend_Click(object sender, EventArgs e)
{
DataPassed?.Invoke(txtInput.Text); // 触发事件
}
}
父窗口订阅事件:
private void btnOpenChild_Click(object sender, EventArgs e)
{
var childForm = new ChildForm();
childForm.DataPassed += (data) =>
{
// 确保在主线程更新 UI
this.Invoke((MethodInvoker)delegate
{
lblResult.Text = $"接收的值:{data}";
});
};
childForm.Show(); // 非模态显示
}
方法 3:通过委托回调(解耦推荐)
场景:希望完全解耦父子窗口,通过回调传递数据。
步骤:
子窗口接收委托参数:
public partial class ChildForm : Form
{
private readonly Action<string> _callback;
// 构造函数接收回调委托
public ChildForm(Action<string> callback)
{
InitializeComponent();
_callback = callback;
}
private void btnOK_Click(object sender, EventArgs e)
{
_callback?.Invoke(txtInput.Text);
this.Close();
}
}
父窗口调用时传入回调:
private void btnOpenChild_Click(object sender, EventArgs e)
{
var childForm = new ChildForm((data) =>
{
lblResult.Text = $"接收的值:{data}";
});
childForm.Show();
}
方法 4:通过父窗口引用(直接但耦合)
场景:快速实现,但父子窗口会紧密耦合。
步骤:
子窗口构造函数接收父窗口引用:
public partial class ChildForm : Form
{
private readonly MainForm _parentForm;
public ChildForm(MainForm parent)
{
InitializeComponent();
_parentForm = parent;
}
private void btnSend_Click(object sender, EventArgs e)
{
_parentForm.UpdateLabel(txtInput.Text);
this.Close();
}
}
父窗口定义公共方法供子窗口调用:
public partial class MainForm : Form
{
public void UpdateLabel(string text)
{
lblResult.Text = $"接收的值:{text}";
}
private void btnOpenChild_Click(object sender, EventArgs e)
{
var childForm = new ChildForm(this);
childForm.Show();
}
}
方法 5:使用静态类或单例(全局共享数据)
场景:多个窗口需要共享数据,但需谨慎使用以避免过度耦合。
步骤:
定义静态数据容器:
public static class DataContainer
{
public static string SharedData { get; set; }
}
子窗口设置数据:
private void btnSave_Click(object sender, EventArgs e)
{
DataContainer.SharedData = txtInput.Text;
this.Close();
}
父窗口读取数据(如通过事件或定时检查):
private void btnOpenChild_Click(object sender, EventArgs e)
{
var childForm = new ChildForm();
childForm.FormClosed += (s, args) =>
{
lblResult.Text = $"接收的值:{DataContainer.SharedData}";
};
childForm.Show();
}
对比与选择
方法 优点 缺点 适用场景
公共属性 简单直接 仅适用于模态窗口 简单数据传递
事件 解耦,支持非模态窗口 需处理线程安全 实时数据更新
委托回调 高度解耦,灵活 需要预先定义回调逻辑 复杂交互或插件式架构
父窗口引用 快速实现 高耦合,不利于维护 快速原型开发
静态类 全局访问 数据共享可能导致混乱 小型应用或临时解决方案
最佳实践建议
解耦优先:优先使用 事件 或 委托回调,减少窗口间的直接依赖。
线程安全:非模态窗口传值时,使用 Control.Invoke 确保 UI 更新在主线程。
资源释放:非模态窗口及时注销事件,避免内存泄漏。
数据验证:在子窗口关闭前验证数据有效性,避免传递无效值。
通过以上方法,你可以根据具体需求选择最适合的子窗口传值方案。
查看更多关于C#的WINFORM中子窗口传值给父窗口的详细内容...