如何实现ERP系统中Form1与Form2间的数据共享及ToolStrip跨窗体操作?
解决ERP系统主窗体ToolStrip跨子窗体数据保存问题
以下是几种实用的实现方案,可根据你的系统复杂度选择:
方案1:数据模型+委托事件(低耦合,推荐)
步骤1:定义数据实体类
先抽象子窗体的输入数据为实体类,作为窗体间的数据传递载体:
public class Product { public string ProductName { get; set; } public decimal Price { get; set; } // 对应Form2的其他输入字段 }
步骤2:子窗体Form2暴露操作方法与事件
在Form2中封装数据获取、保存逻辑,并定义事件通知主窗体保存结果:
public partial class Form2 : Form { // 公开获取输入数据的方法 public Product GetInputData() { return new Product { ProductName = txtProductName.Text.Trim(), Price = decimal.TryParse(txtPrice.Text, out var price) ? price : 0 }; } // 定义保存完成事件,通知主窗体结果 public event EventHandler<bool> SaveFinished; // 内部数据库保存逻辑 private bool SaveToDb(Product data) { try { // 示例:用EF Core保存 using (var db = new ErpDbContext()) { db.Products.Add(data); db.SaveChanges(); return true; } } catch (Exception ex) { // 异常日志记录 return false; } } // 供主窗体调用的公开保存方法 public void ExecuteSave() { var inputData = GetInputData(); bool success = SaveToDb(inputData); SaveFinished?.Invoke(this, success); } }
步骤3:主窗体Form1绑定ToolStrip事件
在Form1中跟踪子窗体实例,点击保存按钮时触发子窗体的保存操作:
public partial class Form1 : Form { private Form2 _activeEditForm; // 新增按钮打开Form2 private void tsBtnAdd_Click(object sender, EventArgs e) { _activeEditForm = new Form2(); _activeEditForm.FormClosed += (s, args) => _activeEditForm = null; _activeEditForm.Show(); } // 保存按钮触发子窗体保存 private void tsBtnSave_Click(object sender, EventArgs e) { if (_activeEditForm != null && _activeEditForm.Visible) { _activeEditForm.ExecuteSave(); // 订阅保存结果事件 _activeEditForm.SaveFinished += (s, success) => { MessageBox.Show(success ? "保存成功" : "保存失败"); if (success) { // 刷新主窗体数据列表等后续操作 } }; } else { MessageBox.Show("无活跃的编辑窗体"); } } }
方案2:接口标准化(高复用,适合多子窗体场景)
如果你的ToolStrip需要控制多个不同的子窗体,可通过接口统一操作规范:
步骤1:定义通用编辑窗体接口
public interface IEditableForm { bool ValidateInput(); // 验证输入合法性 object GetFormData(); // 获取输入数据 bool SaveFormData(object data); // 保存数据 }
步骤2:子窗体实现接口
Form2实现上述接口,封装自身的验证、数据处理逻辑:
public partial class Form2 : Form, IEditableForm { public bool ValidateInput() { if (string.IsNullOrWhiteSpace(txtProductName.Text)) { MessageBox.Show("请输入产品名称"); return false; } // 其他输入验证逻辑 return true; } public object GetFormData() { return new Product { ProductName = txtProductName.Text.Trim(), Price = decimal.TryParse(txtPrice.Text, out var price) ? price : 0 }; } public bool SaveFormData(object data) { if (data is Product product) { try { using (var db = new ErpDbContext()) { db.Products.Add(product); db.SaveChanges(); return true; } } catch { return false; } } return false; } }
步骤3:主窗体ToolStrip通用化处理
主窗体无需跟踪具体子窗体实例,直接通过接口查找活跃窗体:
private void tsBtnSave_Click(object sender, EventArgs e) { var activeForm = Application.OpenForms.OfType<IEditableForm>().FirstOrDefault(f => f.Visible); if (activeForm != null) { if (activeForm.ValidateInput()) { var data = activeForm.GetFormData(); bool success = activeForm.SaveFormData(data); MessageBox.Show(success ? "保存成功" : "保存失败"); if (success) { // 刷新主界面数据 } } } else { MessageBox.Show("无可保存的编辑窗体"); } }
注意事项
- 避免直接在主窗体操作子窗体的控件,通过数据实体或接口解耦
- 若ToolStrip需要全局复用,可将其封装为
UserControl,暴露事件委托供宿主窗体绑定 - 数据库操作建议封装为单独的服务层,避免窗体直接操作数据库
内容的提问来源于stack exchange,提问作者Jack C
相关产品推荐
相关产品推荐

