如何在usercontrol C#中以另一种forms调用mainform方法

我在c#中使用windowsFrom。 我试图在用户控件中的一个中调用mainfrom方法。 我有这样的主人

namespace Project { public partial class MainForm : Form { public MainForm() { InitializeComponent(); } public void TempCommand() { StartTemp(); } } } 

我在用户控件中单击了按钮。 当我点击该按钮时,它将打开另一个表单。 我在用户控件中有这样的代码。

  private TempCalib _tempCalib = new TempCalib(); private void calibBtn_Click(object sender, EventArgs e) { _tempCalib.Show(); } 

它将打开另一个,我有一个按钮。 当我点击此处的“确定”按钮时,我需要调用mainfrom方法。

 namespace Project { public partial class TempCalib : Form { public TempCalib() { InitializeComponent(); } private void OkButton_Click(object sender, EventArgs e) { // I need to call the mainfrom "TempCommand" method here. this.Hide(); } } } 

任何人都可以帮我如何做到这一点。

谢谢。

快速回答

只需在辅助表单中添加对主表单的引用:

 public partial class TempCalib : Form { private MainForm _main public TempCalib(MainForm main) : this() { _main = main; } /// Other stuffs } 

然后在构造辅助表单时指定值:

 private TempCalib _tempCalib; private void calibBtn_Click(object sender, EventArgs e) { if (_tempCalib == null) _tempCalib = new TempCalib(this); _tempCalib.Show(); } 

如果calibBtn_Click不在MainForm (但它在UserControl里面),那么你可以用以下_tempCalib替换_tempCalib初始化:

 _tempCalib = new TempCalib((MainWindow)FindForm()); 

然后,您就可以调用主要表单:

 private void OkButton_Click(object sender, EventArgs e) { _main.TempCommand(); this.Hide(); } 

注意:这只是一个选项,你可以创建一个属性来保存MainForm引用(这样二级forms可以重用,它会更加设计友好)而且TempCalib不是UserControl而是一个Form (非常原始但是对于UserControl你可以只检查其父表格并将其转换为正确的类型)。

改进

这种引用通常是警报。 通常,UI组件不应该如此耦合,并且公共Form的方法经常执行某些操作是表明您在Form有太多逻辑的信号。 如何改善这个?

1. DECOUPLE CONTROLS 。 那么第一步可能是将它们分离一点,只需在TempCalib添加一个事件并使MainForm它的接收器:

 public partial class TempCalib : Form { public event EventHandler SomethingMustBeDone; private void OkButton_Click(object sender, EventArgs e) { OnSomethingMustBeDone(EventArgs.Empty); / TO DO this.Hide(); } } 

然后在MainForm

 private TempCalib _tempCalib; private void calibBtn_Click(object sender, EventArgs e) { if (_tempCalib == null) { _tempCalib = new TempCalib(); _tempCalib.SomethingMustBeDone += _tempCalib_SomethingMustBeDone; // In _tempCalib_SomethingMustBeDone you'll invoke proper member // and possibly hide _tempCalib (remove it from OkButton_Click) } _tempCalib.Show(); } 

2.从控制中解除逻辑 。 UI经常变化,逻辑不变(当变化可能与UI并行时)。 这只是第一步(现在TempCalib不知道谁将使用它)。 下一步(在表单中发生太多事情时执行)是从表单本身中删除这种逻辑。 小例子(非常原始),保持TempCalib像以前一样(使用事件)并将MainForm更改为被动

 public partial class MainForm : Form { public event EventHandler Calibrate; protected virtual void OnCalibrate(EventArgs e) { // TODO } } 

现在让我们创建一个类来控制流和逻辑:

 public class MyTaskController { private MainForm _main; private TempCalib _tempCalib; public void Start() { _main = new MainForm(); _main.Calibrate += OnCalibrationRequested; _main.Show(); // Or whatever else } private void OnCalibrationRequested(object sender, EventArgs e) { if (_tempCalib == null) { _tempCalib = new TempCalib(); _tempCalib.SomethingMustBeDone += OnSomethingMustBeDone(); } _tempCalib.Show(); } private OnSomethingMustBeDone(object sender, EventArgs e) { // Perform the task here then hide calibration window _tempCalib.Hide(); } } 

是的,您需要编写更多代码,但这会从UI本身解耦逻辑 (例如,对动作的响应)。 当程序增长时,这将帮助您根据需要更改UI,保持逻辑不知道(并在一个明确定义的位置)。 我甚至没有提到这将允许您使用不同的资源 (人)来编写逻辑和UI(或者为不同的UI,WinForms和WPF 重用逻辑)。 无论如何,IMO最明显和最好的回报是…… 可读性 :你总是知道逻辑在哪里以及UI管理在哪里,没有搜索,没有混乱,没有错误。

3.从实施中解决逻辑问题 。 您还可以执行更多步骤(需要时)。 您的控制器仍然知道具体类型( MainFormTempCalib )。 如果您需要在运行时选择不同的表单(例如,要具有复杂的接口和简化的接口或使用依赖项注入),则必须使用接口对控制器进行分离。 举个例子:

 public interface IUiWindow { void Show(); void Hide(); } public interface IMainWindow : IUiWindow { event EventHandler Calibrate; } public interface ICalibrationWindow : IUiWindow { event EventHandler SomethingMustBeDone; } 

您可以使用在UserControl声明的自定义事件。 然后您的表单需要处理此事件并调用您要调用的方法。 如果您让UserControl访问您的表单,您将彼此硬链接,这会降低UserControl可重用性。

例如,在TempCalib

 public delegate void OkClickedHandler(object sender, EventArgs e); public event OkClickedHandler OkClicked; private void OkButton_Click(object sender, EventArgs e) { // Make sure someone is listening to event if (OkClicked == null) return; OkClicked(sender, e); this.Hide(); } 

在你的主要forms:

 private void Mainform_Load(object sender, EventArgs e) { _tempCalib.OkClicked += CalibOkClicked; } private void CalibOkClicked(Object sender, EventArgs e) { StartTemp(); } 

您可以在usercontrol中创建一个事件,并在mainform中订阅它。 这是通常的方式。

Form1代码:

  UserControl1 myusercontrol = new UserControl1(); public void TabClose(Object sender,EventArgs e) { int i = 0; i = tabControl1.SelectedIndex; tabControl1.TabPages.RemoveAt(i); } private void Form1_Load(object sender, EventArgs e) { myusercontrol.Dock = DockStyle.Fill; TabPage myTabPage = new TabPage(); myTabPage.Text = "Student"; myTabPage.Controls.Add(myusercontrol); tabControl1.TabPages.Add(myTabPage); myusercontrol.OkClick += TabClose; } 

UserControl1代码:

  public delegate void OkClickedHandler(Object sender, EventArgs e); public partial class UserControl1 : UserControl { public event OkClickedHandler OkClick; public UserControl1() { InitializeComponent(); } private void button3_Click(object sender, EventArgs e) { if (OkClick == null) return; OkClick(sender, e); } } 

试试这个:

从用户控制试试这个:

 MainForm form = this.TopLevelControl as MainForm; form.TempCommand();