简体   繁体   中英

How to call mainform method in another form in usercontrol C#

I am working with windowsFrom in c#. I am trying to call mainfrom method in one of the from in user control. I have mainfrom like this

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

    public void TempCommand()
      {
       StartTemp();
      }
   }
 }

I have the button click in the user control. When i click that button then it will open another form. I have the code like this in the user control.

   private TempCalib _tempCalib = new TempCalib();

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

it will open another from and i have one button in that from. I need to call mainfrom method when i click "Ok" button in this from.

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();
    }


   }
 }

Can anyone help me how to do this.

Thanks.

Quick answer

Just add a reference to the primary form in your secondary form:

public partial class TempCalib : Form
{
    private  MainForm _main

    public TempCalib(MainForm main) : this()
    {
        _main = main;
    }

    /// Other stuffs
}

Then assign value when you construct your secondary form:

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

     _tempCalib.Show();
}

If calibBtn_Click isn't inside MainForm (but it's inside a UserControl on it) then you can replace _tempCalib initialization with:

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

You'll be then able to call the primary form:

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

Notes: this is just one option, you may create a property to hold MainForm reference (so secondary form can be reused and it'll be more designer friendly) moreover TempCalib is not an UserControl but a Form (pretty raw but for an UserControl you may just check its parent Form and cast it to proper type).

Improvements

Such kind of references are often an alert. Usually UI components shouldn't not be so coupled and a public Form 's method to perform something very often is the signal that you have too much logic in your Form . How to improve this?

1. DECOUPLE CONTROLS . Well a first step may be to decouple them a little bit, just add an event in TempCalib and make MainForm its receiver:

public partial class TempCalib : Form
{
    public event EventHandler SomethingMustBeDone;

    private void OkButton_Click(object sender, EventArgs e)
    {
        OnSomethingMustBeDone(EventArgs.Empty); / TO DO
       this.Hide();
    }
}

Then in 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. DECOUPLE LOGIC FROM CONTROLS . UI changes pretty often, logic not (and when it changes probably isn't in parallel with UI). This is just the first step (now TempCalib isn't aware of who will use it). Next step (to be performed when too much things happen inside your form) is to remove this kind of logic from the form itself. Little example (very raw), keep TempCalib as before (with the event) and change MainForm to be passive :

public partial class MainForm : Form
{
    public event EventHandler Calibrate;

    protected virtual void OnCalibrate(EventArgs e)
    {
        // TODO
    }
}

Now let's create a class to control the flow and logic:

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();
    }    
}

Yes, you'll need to write much more code but this will decouple logic (what to do as response to an action, for example) from UI itself. When program grows up this will help you to change UI as needed keeping logic unaware of that (and in one well defined place). I don't even mention that this will allow you to use different resources (people) to write logic and UI (or to reuse logic for different UI, WinForms and WPF, for example). Anyway IMO the most obvious and well repaid benefit is... readability : you'll always know where logic is and where UI management is, no search, no confusion, no mistakes.

3. DECOUPLE LOGIC FROM IMPLEMENTATION . Again you have more steps to perform (when needed). Your controller is still aware of concrete types ( MainForm and TempCalib ). In case you need to select a different form at run-time (for example to have a complex interface and a simplified one or to use dependency injection) then you have to decouple controller using interfaces. Just an example:

public interface IUiWindow
{
    void Show();
    void Hide();
}

public interface IMainWindow : IUiWindow
{
    event EventHandler Calibrate;
}

public interface ICalibrationWindow : IUiWindow
{
    event EventHandler SomethingMustBeDone;
}

You create an event in your usercontrol and subscribe to this in the mainform. That is the usual way.

You could use a custom event that is declared in your UserControl . Then your form needs to handle this event and call the method you want to call. If you let the UserControl access your form, you are hard-linking both with each other which decreases reusability of your UserControl .

For example, in 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();       
}

in your mainform:

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

private void CalibOkClicked(Object sender, EventArgs e)
{
    StartTemp();
}

Form1 Code:

    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 Code:

     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);

    }
}

Try this:

From user control try this:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM