How do I pass a value from a child back to the parent form? I have a string that I would like to pass back to the parent.
I launched the child using:
FormOptions formOptions = new FormOptions();
formOptions.ShowDialog();
Create a property (or method) on FormOptions, say GetMyResult:
using (FormOptions formOptions = new FormOptions())
{
formOptions.ShowDialog();
string result = formOptions.GetMyResult;
// do what ever with result...
}
If you're just using formOptions to pick a single value and then close, Mitch's suggestion is a good way to go. My example here would be used if you needed the child to communicate back to the parent while remaining open.
In your parent form, add a public method that the child form will call, such as
public void NotifyMe(string s)
{
// Do whatever you need to do with the string
}
Next, when you need to launch the child window from the parent, use this code:
using (FormOptions formOptions = new FormOptions())
{
// passing this in ShowDialog will set the .Owner
// property of the child form
formOptions.ShowDialog(this);
}
In the child form, use this code to pass a value back to the parent:
ParentForm parent = (ParentForm)this.Owner;
parent.NotifyMe("whatever");
The code in this example would be better used for something like a toolbox window which is intended to float above the main form. In this case, you would open the child form (with .TopMost = true) using .Show() instead of .ShowDialog().
A design like this means that the child form is tightly coupled to the parent form (since the child has to cast its owner as a ParentForm in order to call its NotifyMe method). However, this is not automatically a bad thing.
You can also create a public property.
// Using and namespace...
public partial class FormOptions : Form
{
private string _MyString; // Use this
public string MyString { // in
get { return _MyString; } // .NET
} // 2.0
public string MyString { get; } // In .NET 3.0 or newer
// The rest of the form code
}
Then you can get it with:
FormOptions formOptions = new FormOptions();
formOptions.ShowDialog();
string myString = formOptions.MyString;
You can also create an overload of ShowDialog in your child class that gets an out parameter that returns you the result.
public partial class FormOptions : Form
{
public DialogResult ShowDialog(out string result)
{
DialogResult dialogResult = base.ShowDialog();
result = m_Result;
return dialogResult;
}
}
Use public property of child form
frmOptions {
public string Result; }
frmMain {
frmOptions.ShowDialog(); string r = frmOptions.Result; }
Use events
frmMain {
frmOptions.OnResult += new ResultEventHandler(frmMain.frmOptions_Resukt);
frmOptions.ShowDialog(); }
Use public property of main form
frmOptions {
public frmMain MainForm; MainForm.Result = "result"; }
frmMain {
public string Result;
frmOptions.MainForm = this;
frmOptions.ShowDialog();
string r = this.Result; }
Use object Control.Tag; This is common for all controls public property which can contains a System.Object. You can hold there string or MyClass or MainForm - anything!
frmOptions {
this.Tag = "result": }
frmMain {
frmOptions.ShowDialog();
string r = frmOptions.Tag as string; }
Well I have just come across the same problem here - maybe a bit different. However, I think this is how I solved it:
in my parent form I declared the child form without instance e.g. RefDateSelect myDateFrm; So this is available to my other methods within this class/ form
next, a method displays the child by new instance:
myDateFrm = new RefDateSelect();
myDateFrm.MdiParent = this;
myDateFrm.Show();
myDateFrm.Focus();
my third method (which wants the results from child) can come at any time & simply get results:
PDateEnd = myDateFrm.JustGetDateEnd();
pDateStart = myDateFrm.JustGetDateStart();`
Note: the child methods JustGetDateStart() are public within CHILD as:
public DateTime JustGetDateStart()
{
return DateTime.Parse(this.dtpStart.EditValue.ToString());
}
I hope this helps.
For Picrofo EDY
It depends, if you use the ShowDialog() as a way of showing your form and to close it you use the close button instead of this.Close(). The form will not be disposed or destroyed, it will only be hidden and changes can be made after is gone. In order to properly close it you will need the Dispose() or Close() method. In the other hand, if you use the Show() method and you close it, the form will be disposed and can not be modified after.
If you are displaying child form as a modal dialog box, you can set DialogResult property of child form with a value from the DialogResult enumeration which in turn hides the modal dialog box, and returns control to the calling form. At this time parent can access child form's data to get the info that it need.
For more info check this link:
http://msdn.microsoft.com/en-us/library/system.windows.forms.form.dialogresult(v=vs.110).aspx
i had same problem i solved it like that , here are newbies step by step instruction
first create object of child form it top of your form class , then use that object for every operation of child form like showing child form and reading value from it.
example
namespace ParentChild
{
// Parent Form Class
public partial class ParentForm : Form
{
// Forms Objects
ChildForm child_obj = new ChildForm();
// Show Child Forrm
private void ShowChildForm_Click(object sender, EventArgs e)
{
child_obj.ShowDialog();
}
// Read Data from Child Form
private void ReadChildFormData_Click(object sender, EventArgs e)
{
int ChildData = child_obj.child_value; // it will have 12345
}
} // parent form class end point
// Child Form Class
public partial class ChildForm : Form
{
public int child_value = 0; // variable where we will store value to be read by parent form
// save something into child_value variable and close child form
private void SaveData_Click(object sender, EventArgs e)
{
child_value = 12345; // save 12345 value to variable
this.Close(); // close child form
}
} // child form class end point
} // name space end point
Many ways to skin the cat here and #Mitch's suggestion is a good way. If you want the client form to have more 'control', you may want to pass the instance of the parent to the child when created and then you can call any public parent method on the child.
I think the easiest way is to use the Tag property
in your FormOptions class set the Tag = value you need to pass
and after the ShowDialog method read it as
myvalue x=(myvalue)formoptions.Tag;
When you use the ShowDialog() or Show() method, and then close the form, the form object does not get completely destroyed (closing != destruction). It will remain alive, only it's in a "closed" state, and you can still do things to it.
The fastest and more flexible way to do that is passing the parent to the children from the constructor as below:
Declare a property in the parent form:
public string MyProperty {get; set;}
Declare a property from the parent in child form:
private ParentForm ParentProperty {get; set;}
Write the child's constructor like this:
public ChildForm(ParentForm parent){
ParentProperty= parent;
}
Change the value of the parent property everywhere in the child form:
ParentProperty.MyProperty = "New value";
It's done. the property MyProperty in the parent form is changed. With this solution, you can change multiple properties from the child form. So delicious, no?!
Related
I have a value(let CompanyId) in a child form. I want to pass this value in a level of the MDI parent form.
In child form I retrieve data from database in a datagrid view.
Now I select a value from datagrid view.
string SkillName = dataGridView1.CurrentRow.Cells["SHORTS"].Value.ToString();
Now I want to pass this SkillName value to MDI parent form.
How Can I do this?
there are literally countless ways to do it. it all depend on what you want to do and why.
#f0x way is good, but also use a public parameter, create an event and pop it when you want, set a flag(could be a global flag) and more.
if you want to pass simple data from parent to child you can do it by, as f0x said, in the constructor, or make the child register an event you execute, that send a string/int/etc., and then you can execute the event whenever you(the parent) want and the child immediately handle that data.
it can go the other way around: when the parent create the child, it register on an event the child fire...
here is an example:
public partial class Form1 : Form
{
public void RegisterSon()
{
ChildForm frm = new ChildForm();
frm.MyEventChild += new MyEvntHndler(frm_MyEventChild);
}
void frm_MyEventChild(string data)
{
}
}
public delegate void MyEvntHndler(string data);
public class ChildForm: Form
{
public event MyEvntHndler MyEventChild;
private void button1_Clicked(object sender, EventArgs e)
{
if (MyEventChild != null)
{
MyEventChild("This is my data");
}
}
}
The easiest way would be to pass the companyId as a parameter to the constructor of the form.
For example in the company form:
public partial class CompanyForm : Form
{
public CompanyForm(int companyId)
{
InitializeComponent();
}
}
When you call the new form simply pass the value from your calling form:
var form = new CompanyForm(10); // '10' the id
form.MdiParent = this;
form.Show();
I have a custom message box (a winform basically) which pops up on the center of the calling form, like this:
public partial class Form1 : Form
{
private void button1_Click(object sender, EventArgs e)
{
MsgBox.Show(this, "asdsdfsdf");
}
}
Here I pass this (Form1) as the owner of MsgBox. Now I know where to position the MsgBox form since I am passing the parent form (Form1) as well.
But I need this custom messagebox to align itself (center to parent form) even if called from other classes, for eg,
public class Computer
{
public void Do(int i)
{
MsgBox.Show(i.ToString());
}
}
The problem here is I can't pass reference of the parent form to MsgBox class. So here I wont be able to position the custom box. What I would love to have is an ability for MsgBox class to determine which is the last form class in the call stack?
I tried this:
public partial class MsgBox : Form
{
private void X()
{
StackTrace df = new StackTrace();
foreach (var item in df.GetFrames())
{
var type = item.GetMethod().DeclaringType;
if (type.BaseType == typeof(Form))
{
IWin32Window w = //how to get the form instance here??
//------------
break;
}
}
}
}
I do get upto the inner if clause; the problem is that I dont know how to get the form instance or the IWin32Window handle of the form from the type variable.. Is there something I can do to get the instances itself of the classes rather than the types?
A Big Edit: Apologies, that's been a big mistake I made to say that getting the reference of parent form is to center the child form. I need parent form's handle in MsqBox instance as it does other things as well. In short I need the parent form in child form without reference of parent not being passed. Is it possible?
You could try centering your MessageBox on Form.ActiveForm.
The solution:
Keep the private Form Parent { get; private set; } property in each MsgBox class instance.
Create MsgBox.ActiveForm { get { .. } } static property which will pick the Form.ActiveForm and if it is of type MsgBox then return it's parent.
Static property of MsgBox class:
public static Form ActiveForm
{
get
{
return Form.ActiveForm == null ? null :
Form.ActiveForm is MsgBox ? ((MsgBox)Form.ActiveForm).Parent :
Form.ActiveForm;
}
}
This is one way of doing it, thanks #Joe:
public static Form GetLastForm()
{
if (Form.ActiveForm != null && !(Form.ActiveForm is MsgBox))
return Form.ActiveForm;
var openForms = Application.OpenForms.Cast<Form>().Where(f => !(f is MsgBox));
if (openForms.Count > 0)
return openForms[openForms.Count - 1];
return null;
}
I had problem getting the correct parent form thru stack trace approach. Here the basic confusion is to identify if I wanted the current active form, or the last opened form, or the form that caused the MsgBox to pop up. All three can be different, and I went for stack trace approach so as to get third one. Depending on stack trace was frustrating. I just now get the active form, if not I retrieve the last opened form. Application.OpenForms have the forms in exact correct order forms were opened.
i have opened a mainform and call a child form like
Form4 f = new Form4();
f.Owner = this;
f.Show(this);
in form4, user selects a text file, the contents of which are to be displayed in a textBox1 of mainform
i was trying something like
Owner.textBox1.Text = "file contents";
but it does'nt work
The best way to link different forms together is via events. Create an event in Form4 like FileSelected and then do something like this:
Form4 f = new Form4();
f.FileSelected += (owner, args) => {
textBox1.Text = args.FileName;
};
f.Show(this);
Besides this is really bad design, you need to make textBox1 a public member of your main form and cast f.Owner to the main form type.
Like:
Form4 f = new Form4();
f.Owner = this;
f.Show(this);
// Inside Form4
MainForm main = this.Owner as MainForm;
if (main != null) main.textBox1.Text...
A best practice would be to define yourself a property that would itself set the Text property of your private control. Here's an instance:
public partial class MainForm : Form {
public string ContentDescription {
set {
textBox1.Text = value.trim();
}
}
}
Then after, you'll be able to access this property through type-casting to your particular type:
public partial class SecondaryForm : Form {
public MainForm OwnerForm {
get {
return (MainForm)this.Owner;
}
}
public void someMethod() {
OwnerForm.ContentDescription = "file contents";
}
}
Remember that in C#, every Control is declared private. So, to access it, the best practice is to define a property that will grant you the required access to it. Making a member public is generally not a good idea, depending on what you're trying to achieve.
EDIT For the parse method, perhaps should you consider making it public or internal so that you may access it through the correctly type-casted Owner property of your child form.
Making a hlper class might be the right solution though, so it is not GUI dependent.
In Form4 you can cast Owner to the correct type:
var o = (Form1) this.Owner;
o.textBox1.Text = "file contents";
For this to work, the owner must be of type Form1 and textBox1 on that type must be a public member or property.
As Andrew already gave the correct solution for event driven, there is also a sync (or blocking) method available:
Form4 f = new Form4;
if(f.ShowDialog() == DialogResult.OK)
{
textBox1.Text = f.FileName;
}
You will need to set the "modifiers" to at least public for the properties of the control to be able to have access to it.
alt text http://gabecalabro.com/gabe/Capture.PNG
In code behind file of the main window of WPF application I have a method quering a database with LINQ to SQL and writing results to an ObservableCollection:
public void GetStateByDate(string shcode)
{
MydbDataContext contextSts = new MydbDataContext();
_ShAvaQuCollection.Clear();
var sts = from p in contextSts.SAties where p.ShID == shcode select p;
foreach (var p in sts)
_ShAvaQuCollection.Add(new ShAvaQu
{
ShCode = p.ShID,
SiID = p.SiID,
PrCat = p.PrCat
});
}
When I call this method from the same code behind file (the same window), everything is OK.
If I call this method from another window, using an instanse of the main window, ObservableCollection remains empty.:
SWindow sw = new SWindow();
sw.GetStateByDate(stringpar);
What is the reason for this? Does in this case method create yet another instance of ObservableCollection?
(I can see in debugger that sw._ShAvaQuCollection contains values. Is sw._ShAvaQuCollection not the same instanse of collection as _ShAvaQuCollection? If yes, how it can be resolved?)
Edited (added)
The ObservableCollection declared this way:
ObservableCollection<ShAvaQu> _ShAvaQuCollection =
new ObservableCollection<ShAvaQu>();
public ObservableCollection<ShAvaQu> ShAvaQuCollection
{ get { return _ShAvaQuCollection; } }
public class ShAvaQu
{
public string ShCode { get; set; }
public string SiID { get; set; }
public int PrCat { get; set; }
}
I call the method from a window, where another collection ShQuCollection displayed through ListView. In SelectionChanged event handler I take an argument for this database quering:
private void ShSelList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
SWindow sw = new SWindow();
string str = sw.ShQuCollection[ShSelList.SelectedIndex].ShCode;
sw.GetStateByDate(str);
Close();
}
}
1) Most importantly you shouldn't be calling db logic from you windows / forms. You should abstract it out into another class. Then you could have your method return a observable collection.
However in your case I am assuming that you are trying to use the secondary form to reload / load the collection and you want it used on your primary form. The problem with this is you are creating a new instance of the form so your collection is being populated but not on your main form but a copy.
There are a couple ways you can try to get around that.
1) Make the method static and your observable collection static so that it updates a single instance.
2) Pass an instance handle of your primary form into your secondary form so that you re-use the instance you already have. This would be preferable so that you are not creating new instances all over the place.
In the constructor of the second form you could pass in the instance of your primary window so then you can use it directly. This should solve your problem.
UPDATE: Here is some code samples. Basically there are many ways to pass a reference.
You could do it like this with a constructor:
// This is the constructor for your second window
private Window _parentHandle;
public SecondWindow(Window obj)
{
this._parentHandle = obj;
}
Then from your primary form that has the method you would open that window like this.
SecondWindow w = new SecondWindow(this);
w.Show();
Now your second window has a direct handle to your first window so you can call your method on that variable and it will update.
Another way is to have a public Setter method on your second window as well.
public Window ParentContext
{
get { return this._parentHandle; }
set { this._parentHandle = value; }
}
Then you could create your form instance like this:
SecondWindow w = new SecondWindow(); // so just like normal
w.ParentContext = this; // set the instance to the calling form
w.Show();
That is the basics. This type of scenario works in just about any scenario where you need to pass a reference.
Hope that helps.
I have a Parent Form that holds a "HUD" with First Name, Last Name, etc. One of the child forms is a Search Form. When the user selects a member from the results that are displayed in a DataGrid I want the pertinent information to fill in the HUD. I created a HUD class with variables for each value and a method called UpdateHUD(). I am unsure how to get this working. I have a reference to the Search Form of the Parent form containing the HUD, like so:
public frmWWCModuleHost _frmWWCModuleHost;
This is the code I use to embed forms. I am not using MDI.
public static void ShowFormInContainerControl(Control ctl, Form frm)
{
frm.TopLevel = false;
frm.FormBorderStyle = FormBorderStyle.None;
frm.Dock = DockStyle.Fill;
frm.Visible = true;
ctl.Controls.Add(frm);
}
Here is the code I am running on Cell Click on the Search Form. This is from before I tried implementing the HUD class.
private void dgvSearchResults_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
_frmWWCModuleHost = new frmWWCModuleHost();
_frmWWCModuleHost.tbxHUD_LastName.Text = dgvSearchResults.CurrentRow.Cells[1].FormattedValue.ToString();
_frmWWCModuleHost.tbxHUD_LastName.Invalidate();
_frmWWCModuleHost.FormPaint();
}
Thanks in advance!
~ Patrick
EDIT
dgvSearchResults_CellContentClick is now current. When I step through this code it is getting the correct Value here but it is never updating the actual HUD.
EDIT 2
Is my problem that I am declaring a NEW frmWWCModuleHost instead of passing a ref to the existing? I am still pretty weak in my understanding of this.
EDIT 3
I have "solved" this by doing the following: On the Parent Form where I declare the Child Form I pass this as a param. Then in the constructor of the child form I added _frmWWCModuleHost = m_parent; I have a UpdateHUD() method on my Parent form and I call it from the _CellClick event on the child.
Now to rephrase my question; Is there anything glaringly wrong with doing it this way?
When the child form search completes, raise a "SearchCompleted" event. Then anything (including the parent form) can subscribe to that event and retrieve the details.
See the following NotepadCode for an example:
class ParentForm
{
private readonly ChildForm childForm;
public ParentForm()
{
InitializeComponent();
childForm = new ChildForm();
childForm.SearchCompleted += childForm_SearchCompleted;
}
private void childForm_SearchCompleted(object sender, SearchCompletedEventArgs e)
{
// Update the display
lblName.Text = e.DataToDisplay;
}
}
class ChildForm
{
public event EventHandler<SearchCompletedEventArgs> SearchCompleted;
private void Search(string query)
{
// Do the searching
OnSearchCompleted(new SearchCompletedEventArgs([arg values]));
}
public void OnSearchCompleted(SearchCompletedEventArgs args)
{
if (SearchCompleted != null)
{
SearchCompleted(this, args);
}
}
}
In .NET, Forms are objects like everything else, so you should think of the problem in those terms.
With that, the child form will need access to the parent form. You can provide that by passing the parent form reference to the child form through the constructor, a method, or a field/property (although the constructor makes the most sense).
Then, you can change the values in parent form from the child.
HOWEVER I would say this isn't the best idea. Rather, the child should expose an event indicating that the data changed (as well as the mechanism to get that data) and then the parent should subscribe to that event and update itself with the data when it is fired.
Sometimes in situations like this I'll create a delegate that matches the signature of the method I want to call in the parent class (I think that would be UpdateHUD in your case), and then pass an instance of that delegate (i.e. a reference to UpdateHUD) to the child form (the search form in this case). When the child form is finished accepting input, it invokes the delegate using the data collected on the form.
So, say UpdateHUD is a method in the parent form that looks something like this.
private void UpdateHUD(string firstName, string lastName) {
//...
}
You would create a delegate with the same signature, like this.
public delegate void HUDUpdateHandler(string firstName, string lastName);
Then you would add a HUDUpdateHandler parameter to the constructor of the child form and store it in a private field (for example, this.handler = handler). When your child form is ready to send its data back, you would invoke the child form's private field (this.handler.Invoke(firstNameTextBox.Text, lastNameTextBox.Text), for example). That will invoke UpdateHUD in your parent class using the values from the child class, and you won't have to expose anything.
I find this approach simpler to implement than raising and catching events, and it allows you to keep the internals of your parent class internal.