WinForms技术实践:将父窗体引用传入多子控件是否为良好实践?
优化子窗体与父窗体交互的实现方案
当前实现与问题
你当前通过子窗体基类持有父窗体的Form实例来实现交互,但存在两个核心问题:
- 过度暴露:子窗体可访问父窗体所有公共成员,违反迪米特法则,耦合度高
- 并发风险:多个子窗体同时操作父窗体时,易引发状态不一致或线程安全问题
以下是你的简化实现代码:
public partial class ParentForm : Form { public ParentForm() { InitializeComponent(); } private void Button1_OnClick(object sender, EventArgs e) { new ChildForm1(this).Show(); } // Some other methods } public abstract partial class BaseChildForm : Form { protected readonly Form _parent; public BaseChildForm(Form parent) { _parent = parent; InitializeComponent(); } private void ThisForm_OnAppear(object sender, EventArgs e) { // Do some changes in the parent form through _parent field } // Some other methods as well } public partial class ChildForm1 : BaseChildForm { public ChildForm1(Form parent) : base(parent){} // Overridden abstract methods and other methods // Do some tampering with the parent form } public partial class ChildForm2 : BaseChildForm { public ChildForm2(Form parent) : base(parent){} // Overridden abstract methods and other methods // Do some tampering with the parent form }
优化方案
1. 定义抽象接口限制交互范围
通过创建仅包含子窗体所需操作的接口,让父窗体实现该接口,子窗体仅依赖接口而非完整父窗体类型,缩小暴露范围。
实现代码:
// 定义仅包含子窗体需要的操作的接口 public interface IParentController { void UpdateStatus(string status); bool IsUserLoggedIn { get; } void RefreshDataGrid(); } // 父窗体实现接口 public partial class ParentForm : Form, IParentController { public bool IsUserLoggedIn { get; private set; } public ParentForm() { InitializeComponent(); } private void Button1_OnClick(object sender, EventArgs e) { new ChildForm1(this).Show(); } public void UpdateStatus(string status) { lblStatus.Text = status; } public void RefreshDataGrid() { dataGridView1.DataSource = GetUpdatedData(); } private object GetUpdatedData() { // 业务逻辑实现 return new object(); } } // 修改子窗体基类依赖接口 public abstract partial class BaseChildForm : Form { protected readonly IParentController _parentController; public BaseChildForm(IParentController parentController) { _parentController = parentController; InitializeComponent(); } private void ThisForm_OnAppear(object sender, EventArgs e) { _parentController.UpdateStatus("子窗体已打开"); } } public partial class ChildForm1 : BaseChildForm { public ChildForm1(IParentController parentController) : base(parentController){} public void DoOperation() { if (_parentController.IsUserLoggedIn) { _parentController.RefreshDataGrid(); } } }
优点:严格限制子窗体操作范围,降低耦合,符合面向接口编程原则,实现简单。
2. 使用事件机制解耦子父窗体
子窗体仅触发事件,父窗体自行订阅并处理逻辑,彻底解除子窗体对父窗体的直接依赖。
实现代码:
// 子窗体基类定义事件 public abstract partial class BaseChildForm : Form { public class ParentActionEventArgs : EventArgs { public string StatusMessage { get; set; } public bool NeedRefreshData { get; set; } } public event EventHandler<ParentActionEventArgs> ParentActionRequested; protected virtual void OnParentActionRequested(ParentActionEventArgs e) { ParentActionRequested?.Invoke(this, e); } private void ThisForm_OnAppear(object sender, EventArgs e) { OnParentActionRequested(new ParentActionEventArgs { StatusMessage = "子窗体已打开", NeedRefreshData = false }); } } public partial class ChildForm1 : BaseChildForm { public void DoCriticalOperation() { OnParentActionRequested(new ParentActionEventArgs { StatusMessage = "操作完成,数据已更新", NeedRefreshData = true }); } } // 父窗体订阅事件 public partial class ParentForm : Form { public ParentForm() { InitializeComponent(); } private void Button1_OnClick(object sender, EventArgs e) { var childForm = new ChildForm1(); childForm.ParentActionRequested += ChildForm_ParentActionRequested; childForm.FormClosed += (s, args) => childForm.ParentActionRequested -= ChildForm_ParentActionRequested; childForm.Show(); } private void ChildForm_ParentActionRequested(object sender, BaseChildForm.ParentActionEventArgs e) { lblStatus.Text = e.StatusMessage; if (e.NeedRefreshData) { dataGridView1.DataSource = GetUpdatedData(); } } private object GetUpdatedData() { // 业务逻辑实现 return new object(); } }
优点:子父窗体完全解耦,父窗体统一控制自身状态变更,避免多实例操作冲突。
3. 引入中介者模式(复杂场景适用)
如果存在多子窗体、复杂交互场景,可引入中介者类作为通信枢纽,所有窗体仅与中介者交互,避免形成复杂依赖网络。
实现代码:
// 中介者接口与实现 public interface IFormMediator { void RegisterParent(ParentForm parent); void RegisterChild(BaseChildForm child); void RequestParentUpdate(string status, bool refreshData); } public class FormMediator : IFormMediator { private ParentForm _parent; private List<BaseChildForm> _children = new List<BaseChildForm>(); public void RegisterParent(ParentForm parent) { _parent = parent; } public void RegisterChild(BaseChildForm child) { _children.Add(child); child.FormClosed += (s, args) => _children.Remove(child); } public void RequestParentUpdate(string status, bool refreshData) { _parent.UpdateStatus(status); if (refreshData) { _parent.RefreshDataGrid(); } } } // 父窗体依赖中介者 public partial class ParentForm : Form { private readonly IFormMediator _mediator; public ParentForm(IFormMediator mediator) { _mediator = mediator; _mediator.RegisterParent(this); InitializeComponent(); } private void Button1_OnClick(object sender, EventArgs e) { var childForm = new ChildForm1(_mediator); _mediator.RegisterChild(childForm); childForm.Show(); } public void UpdateStatus(string status) { lblStatus.Text = status; } public void RefreshDataGrid() { dataGridView1.DataSource = GetUpdatedData(); } private object GetUpdatedData() { // 业务逻辑实现 return new object(); } } // 子窗体依赖中介者 public abstract partial class BaseChildForm : Form { protected readonly IFormMediator _mediator; public BaseChildForm(IFormMediator mediator) { _mediator = mediator; InitializeComponent(); } private void ThisForm_OnAppear(object sender, EventArgs e) { _mediator.RequestParentUpdate("子窗体已打开", false); } } public partial class ChildForm1 : BaseChildForm { public ChildForm1(IFormMediator mediator) : base(mediator){} public void DoOperation() { _mediator.RequestParentUpdate("操作完成", true); } }
优点:集中管理交互逻辑,避免窗体间复杂依赖,便于扩展新场景。
缺点:增加额外类,简单场景下冗余。
内容的提问来源于stack exchange,提问作者Zombies are Real
相关产品推荐
相关产品推荐

