How to return a value from a Form in C#?
Asked Answered
T

10

230

I have a main form (let's call it frmHireQuote) that is a child of a main MDI form (frmMainMDI), that shows another form (frmImportContact) via ShowDialog() when a button is clicked.

When the user clicks the 'OK' on frmImportContact, I want to pass a few string variables back to some text boxes on frmHireQuote.

Note that there could be multiple instances of frmHireQuote, it's obviously important that I get back to the instance that called this instance of frmImportContact.

What's the best method of doing this?

Tortoise answered 8/3, 2011 at 14:3 Comment(1)
The canonical method is to expose properties in the child form with the information you need available.Desalvo
A
462

Create some public Properties on your sub-form like so

public string ReturnValue1 {get;set;} 
public string ReturnValue2 {get;set;}

then set this inside your sub-form ok button click handler

private void btnOk_Click(object sender,EventArgs e)
{
    this.ReturnValue1 = "Something";
    this.ReturnValue2 = DateTime.Now.ToString(); //example
    this.DialogResult = DialogResult.OK;
    this.Close();
}

Then in your frmHireQuote form, when you open the sub-form

using (var form = new frmImportContact())
{
    var result = form.ShowDialog();
    if (result == DialogResult.OK)
    {
        string val = form.ReturnValue1;            //values preserved after close
        string dateString = form.ReturnValue2;
        //Do something here with these values

        //for example
        this.txtSomething.Text = val;
    }
}

Additionaly if you wish to cancel out of the sub-form you can just add a button to the form and set its DialogResult to Cancel and you can also set the CancelButton property of the form to said button - this will enable the escape key to cancel out of the form.

Argyres answered 8/3, 2011 at 14:6 Comment(2)
Looks like this.Close() is not needed? it closed anyways without itDenbighshire
@lightsout both DialogResult = DialogResult.OK; and DialogResult = DialogResult.Cancel close (technically hides) a form without ;a Close() statement. The form needs to explicitly disposed of which I believe is why the "using()" above.Bailable
E
19

I normally create a static method on form/dialog, that I can call. This returns the success (OK-button) or failure, along with the values that needs to be filled in.

 public class ResultFromFrmMain {
     public DialogResult Result { get; set; }
     public string Field1 { get; set; }


 }

And on the form:

public static ResultFromFrmMain Execute() {
     using (var f = new frmMain()) {
          var result = new ResultFromFrmMain();
          result.Result = f.ShowDialog();
          if (result.Result == DialogResult.OK) {
             // fill other values
          }
          return result;
     }
}

To call your form;

public void MyEventToCallForm() {
   var result = frmMain.Execute();
   if (result.Result == DialogResult.OK) {
       myTextBox.Text = result.Field1; // or something like that
   }
}
Encroachment answered 8/3, 2011 at 14:12 Comment(2)
Have used this approach also, works well. However prefixing the result class with frm can ( and just did when i read it) lead to confusion...Argyres
I just reused the name from the question (+fast typing). I'll change it to a better name.Encroachment
R
7

Found another small problem with this code... or at least it was problematic when I tried to implement it.

The buttons in frmMain do not return a compatible value, using VS2010 I added the following and everything started working fine.

public static ResultFromFrmMain Execute() {
     using (var f = new frmMain()) {

          f.buttonOK.DialogResult = DialogResult.OK;
          f.buttonCancel.DialogResult = DialogResult.Cancel;

          var result = new ResultFromFrmMain();
          result.Result = f.ShowDialog();

          if (result.Result == DialogResult.OK) {
             // fill other values
          }
          return result;
     }
}

After adding the two button values, the dialog worked great! Thanks for the example, it really helped.

Rhombohedral answered 16/11, 2012 at 4:8 Comment(0)
E
3

delegates are the best option for sending data from one form to another.

public partial class frmImportContact : Form
{
     public delegate void callback_data(string someData);
    public event callback_data getData_CallBack;

    private void button_Click(object sender, EventArgs e)
    {
      string myData = "Top Secret Data To Share";
      getData_CallBack(myData);
    }

}

public partial class frmHireQuote : Form
{
     private void Button_Click(object sender, EventArgs e)
    {

      frmImportContact obj = new frmImportContact();
      obj.getData_CallBack += getData;
    }

    private void getData(string someData)
    {
         MessageBox.Show("someData");
    }
}
Ellaelladine answered 18/4, 2019 at 13:20 Comment(0)
T
2

If you want to pass data to form2 from form1 without passing like new form(sting "data");

Do like that in form 1

using (Form2 form2= new Form2())
{
   form2.ReturnValue1 = "lalala";
   form2.ShowDialog();
}

in form 2 add

public string ReturnValue1 { get; set; }

private void form2_Load(object sender, EventArgs e)
{
   MessageBox.Show(ReturnValue1);
}

Also you can use value in form1 like this if you want to swap something in form1

just in form1

textbox.Text =form2.ReturnValue1
Townshend answered 23/5, 2017 at 10:56 Comment(0)
E
1

I just put into constructor something by reference, so the subform can change its value and main form can get new or modified object from subform.

Elisabeth answered 8/10, 2013 at 12:18 Comment(0)
C
0

I use MDI quite a lot, I like it much more (where it can be used) than multiple floating forms.

But to get the best from it you need to get to grips with your own events. It makes life so much easier for you.

A skeletal example.

Have your own interupt types,

//Clock, Stock and Accoubts represent the actual forms in
//the MDI application. When I have multiple copies of a form
//I also give them an ID, at the time they are created, then
//include that ID in the Args class.
public enum InteruptSource
{
    IS_CLOCK = 0, IS_STOCKS, IS_ACCOUNTS
}
//This particular event type is time based,
//but you can add others to it, such as document
//based.
public enum EVInterupts
{
    CI_NEWDAY = 0, CI_NEWMONTH, CI_NEWYEAR, CI_PAYDAY, CI_STOCKPAYOUT, 
   CI_STOCKIN, DO_NEWEMAIL, DO_SAVETOARCHIVE
}

Then your own Args type

public class ControlArgs
{
    //MDI form source
    public InteruptSource source { get; set; }
    //Interrupt type
    public EVInterupts clockInt { get; set; }
    //in this case only a date is needed
    //but normally I include optional data (as if a C UNION type)
    //the form that responds to the event decides if
    //the data is for it.
    public DateTime date { get; set; }
    //CI_STOCKIN
    public StockClass inStock { get; set; }

}

Then use the delegate within your namespace, but outside of a class

namespace MyApplication
{
public delegate void StoreHandler(object sender, ControlArgs e);
  public partial class Form1 : Form
{
  //your main form
}

Now either manually or using the GUI, have the MDIparent respond to the events of the child forms.

But with your owr Args, you can reduce this to a single function. and you can have provision to interupt the interupts, good for debugging, but can be usefull in other ways too.

Just have al of your mdiparent event codes point to the one function,

        calendar.Friday += new StoreHandler(MyEvents);
        calendar.Saturday += new StoreHandler(MyEvents);
        calendar.Sunday += new StoreHandler(MyEvents);
        calendar.PayDay += new StoreHandler(MyEvents);
        calendar.NewYear += new StoreHandler(MyEvents);

A simple switch mechanism is usually enough to pass events on to appropriate forms.

Cyrille answered 8/3, 2015 at 13:25 Comment(0)
A
0

First you have to define attribute in form2(child) you will update this attribute in form2 and also from form1(parent) :

 public string Response { get; set; }

 private void OkButton_Click(object sender, EventArgs e)
 {
    Response = "ok";
 }

 private void CancelButton_Click(object sender, EventArgs e)
 {
    Response = "Cancel";
 }

Calling of form2(child) from form1(parent):

  using (Form2 formObject= new Form2() )
  {
     formObject.ShowDialog();

      string result = formObject.Response; 
      //to update response of form2 after saving in result
      formObject.Response="";

      // do what ever with result...
      MessageBox.Show("Response from form2: "+result); 
  }
Anzus answered 11/2, 2018 at 19:2 Comment(0)
T
0

I raise an event in the the form setting the value and subscribe to that event in the form(s) that need to deal with the value change.

Tarshatarshish answered 22/12, 2018 at 21:8 Comment(1)
Hey there! Can you elaborate a little more on your answer and possibly provide a code sample to help out future users?Coaster
D
0

You could use the tag property of your dialog form. This is also recommended by the Control.Tag reference:

A common use for the Tag property is to store data that is closely associated with the control.

// Button handler of dialog form:
private void btnOk_Click(object sender, EventArgs e)
{
   // Create a custom result container with some strings to return.
   this.Tag = new MyResult(resultString1, resultString2);
   this.DialogResult = DialogResult.OK; // signals to close dialog
}

And in the calling form:

if (frm.ShowDialog() == DialogResult.OK)
{
    MyResult result = frm.Tag as MyResult;
    ...
}

This works also for WPF dialogs.

Dancer answered 7/5, 2023 at 21:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.