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.
Related
I have two forms, one is the main form and the other is an options form. So say for example that the user clicks on my menu on the main form: Tools -> Options, this would cause my options form to be shown.
My question is how can I send data from my options form back to my main form? I know I could use properties, but I have a lot of options and this seems like an tedious odd thing to do.
So what is the best way?
Form1 triggers Form2 to open. Form2 has overloaded constructor which takes calling form as argument and provides its reference to Form2 members. This solves the communication problem. For example I've exposed Label Property as public in Form1 which is modified in Form2.
With this approach you can do communication in different ways.
Download Link for Sample Project
//Your Form1
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 frm = new Form2(this);
frm.Show();
}
public string LabelText
{
get { return Lbl.Text; }
set { Lbl.Text = value; }
}
}
//Your Form2
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private Form1 mainForm = null;
public Form2(Form callingForm)
{
mainForm = callingForm as Form1;
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
this.mainForm.LabelText = txtMessage.Text;
}
}
(source: ruchitsurati.net)
(source: ruchitsurati.net)
In the comments to the accepted answer, Neeraj Gulia writes:
This leads to tight coupling of the forms Form1 and Form2, I guess instead one should use custom events for such kind of scenarios.
The comment is exactly right. The accepted answer is not bad; for simple programs, and especially for people just learning programming and trying to get basic scenarios to work, it's a very useful example of how a pair of forms can interact.
However, it's true that the coupling that example causes can and should be avoided, and that in the particular example, an event would accomplish the same thing in a general-purpose, decoupled way.
Here's an example, using the accepted answer's code as the baseline:
Form1.cs:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 frm = new Form2();
frm.Button1Click += (s1, e1) => Lbl.Text = ((Form2)s1).Message;
frm.Show();
}
}
The above code creates a new instance of Form2, and then before showing it, adds an event handler to that form's Button1Click event.
Note that the expression (s1, e1) => Lbl.Text = ((Form2)s1).Message is converted automatically by the compiler to a method that looks something similar to (but definitely not exactly like) this:
private void frm_Message(object s1, EventArgs e1)
{
Lbl.Text = ((Form2)s1).Message;
}
There are actually lots of ways/syntaxes to implement and subscribe the event handler. For example, using an anonymous method as the above, you don't really need to cast the sender parameter; instead you can just use the frm local variable directly: (s1, e1) => Lbl.Text = frm.Message.
Going the other way, you don't need to use an anonymous method. You could in fact just declare a regular method just like the compiler-generated one I show above, and then subscribe that method to the event: frm.Button1Click += frm_Message; (where you have of course used the name frm_Message for the method, just as in my example above).
Regardless of how you do it, of course you will need for Form2 to actually implement that Button1Click event. That's very simple…
Form2.cs:
public partial class Form2 : Form
{
public event EventHandler Button1Click;
public string Message { get { return txtMessage.Text; } }
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
EventHandler handler = Button1Click;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
In addition to the event, I've also declared a property Message that exposes the Text property (and only the Text property, and only as read-only in fact) of the txtMessage control. This allows the subscriber to the event to get the value and do whatever it needs to with it.
Note that all that the event does is to alert the subscriber that the button has in fact been clicked. It's up to the subscriber to decide how to interpret or react to that event (e.g. by retrieving the value of the Message property and assigning it to something).
Alternatively, you could in fact deliver the text along with the event itself, by declaring a new EventArgs sub-class and using that for the event instead:
public class MessageEventArgs : EventArgs
{
public string Message { get; private set; }
public MessageEventArgs(string message)
{
Message = message;
}
}
public partial class Form2 : Form
{
public event EventHandler<MessageEventArgs> Button1Click;
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
EventHandler handler = Button1Click;
if (handler != null)
{
handler(this, new MessageEventArgs(txtMessage.Text));
}
}
}
Then the subscriber can just retrieve the message value directly from the event object:
frm.Button1Click += (sender, e) => Lbl.Text = e.Message;
The important thing note in all of the above variations is that at no point does the class Form2 need to know anything about Form1. Having Form1 know about Form2 is unavoidable; after all, that's the object that will create a new Form2 instance and use it. But the relationship can be asymmetrical, with Form2 being usable by any object that needs the features it offers. By exposing the functionality as an event (and optionally with a property), it makes itself useful without limiting its usefulness to only the Form1 class.
The best in this case would be to have some OptionsService class/interface that is accessible via IServiceProvider.
Just add an event when something changes, and the rest of the app can respond to it.
There are lots of ways to perform communication between two Forms.
Some of them have already been explained to you. I am showing you the other way around.
Assuming you have to update some settings from the child form to the parent form. You can make use of these two ways as well :
Using System.Action (Here you simply pass the main forms function as the parameter to the child form like a callback function)
OpenForms Method ( You directly call one of your open forms)
Using System.Action
You can think of it as a callback function passed to the child form.
// -------- IN THE MAIN FORM --------
// CALLING THE CHILD FORM IN YOUR CODE LOOKS LIKE THIS
Options frmOptions = new Options(UpdateSettings);
frmOptions.Show();
// YOUR FUNCTION IN THE MAIN FORM TO BE EXECUTED
public void UpdateSettings(string data)
{
// DO YOUR STUFF HERE
}
// -------- IN THE CHILD FORM --------
Action<string> UpdateSettings = null;
// IN THE CHILD FORMS CONSTRUCTOR
public Options(Action<string> UpdateSettings)
{
InitializeComponent();
this.UpdateSettings = UpdateSettings;
}
private void btnUpdate_Click(object sender, EventArgs e)
{
// CALLING THE CALLBACK FUNCTION
if (UpdateSettings != null)
UpdateSettings("some data");
}
OpenForms Method
This method is easy (2 lines). But only works with forms that are open.
All you need to do is add these two lines where ever you want to pass some data.
Main frmMain = (Main)Application.OpenForms["Main"];
frmMain.UpdateSettings("Some data");
Properties is one option, shared static class - another option, events - another option...
You might try AutoMapper. Keep your options in a separate class and then use AutoMapper to shuttle the data between the class and the form.
Create a Class and put all your properties inside the class .. Create a Property in the parent class and set it from your child (options) form
You can have a function in Form B like so:
public SettingsResults GetNewSettings()
{
if(this.ShowDialog() == DialogResult.Ok)
{
return new SettingsResult { ... };
}
else
{
return null;
}
}
And you can call it like this:
...
using(var fb = new FormB())
{
var s = fb.GetNewSettings();
...
// Notify other parts of the application that settings have changed.
}
MVC, MVP, MVVM -- slight overkill for someone admittedly saying they want tutorials. Those are theories that have entire courses dedicated to them.
As already posted, passing an object around is probably easiest. If treating a class as an object (interchangeable in this sense) is new, then you may want to spend another 2-4 weeks figuring out properties and constructors and such.
I'm not a C# master by any means, but these concepts need to be pretty concrete if you want to go much further beyond passing values between two forms (also classes/objects in their own right). Not trying to be mean here at all, it just sounds like you're moving from something like VB6 (or any language with globals) to something far more structured.
Eventually, it will click.
This is probably sidestepping your problem a little bit, but my settings dialog uses the Application Settings construct. http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx
I can't find a good example that's similar to how I do it (which is actually having an actual class+object), but this covers another way of doing it:
Reading default application settings in C#
A form is a class, just like any other class. Add some public variables to your form class and set them when they click the button to close the form (technically they are just hiding it).
A VB.NET example, but you'll get the idea -
In your OptionsForm class:
Public Option1 as String = ""
etc. Set them when they hit the "Ok" button.
So in your main form, when they hit the "options" button - you create your options form:
OptionsForm.ShowDialog()
when it exits, you harvest your option settings from the public variables on the form:
option1 = OptionsForm.Option1
etc.
The best way to deal with communication between containers is to implement an observer class
The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.
(Wikipedia)
the way i do this is creating an Observer class, and inside it write something like this:
1 public delegate void dlFuncToBeImplemented(string signal);
2 public static event dlFuncToBeImplemented OnFuncToBeImplemented;
3 public static void FuncToBeImplemented(string signal)
4 {
5 OnFuncToBeImplemented(signal);
6 }
so basically: the first line says that there would be a function that somebody else will implement
the second line is creating an event that occurs when the delegated function will call
and the third line is the creation of the function that calls the event
so in your UserControl, you should add a function like this:
private void ObserverRegister()//will contain all observer function registration
{
Observer.OnFuncToBeImplemented += Observer_OnFuncToBeImplemented;
/*and more observer function registration............*/
}
void Observer_OnFuncToBeImplemented(string signal)//the function that will occur when FuncToBeImplemented(signal) will call
{
MessageBox.Show("Signal "+signal+" received!", "Atention!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
and in your Form you should do something like:
public static int signal = 0;
public void button1_Click(object sender, EventArgs e)
{
Observer.FuncToBeImplemented(signal);//will call the event in the user control
}
and now, you can register this function to a whole bunch of other controls and containers and they will all get the signal
I hope this would help :)
I have two forms, one is the main form and the other is an options form. So say for example that the user clicks on my menu on the main form: Tools -> Options, this would cause my options form to be shown.
My question is how can I send data from my options form back to my main form? I know I could use properties, but I have a lot of options and this seems like an tedious odd thing to do.
So what is the best way?
Form1 triggers Form2 to open. Form2 has overloaded constructor which takes calling form as argument and provides its reference to Form2 members. This solves the communication problem. For example I've exposed Label Property as public in Form1 which is modified in Form2.
With this approach you can do communication in different ways.
Download Link for Sample Project
//Your Form1
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 frm = new Form2(this);
frm.Show();
}
public string LabelText
{
get { return Lbl.Text; }
set { Lbl.Text = value; }
}
}
//Your Form2
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private Form1 mainForm = null;
public Form2(Form callingForm)
{
mainForm = callingForm as Form1;
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
this.mainForm.LabelText = txtMessage.Text;
}
}
(source: ruchitsurati.net)
(source: ruchitsurati.net)
In the comments to the accepted answer, Neeraj Gulia writes:
This leads to tight coupling of the forms Form1 and Form2, I guess instead one should use custom events for such kind of scenarios.
The comment is exactly right. The accepted answer is not bad; for simple programs, and especially for people just learning programming and trying to get basic scenarios to work, it's a very useful example of how a pair of forms can interact.
However, it's true that the coupling that example causes can and should be avoided, and that in the particular example, an event would accomplish the same thing in a general-purpose, decoupled way.
Here's an example, using the accepted answer's code as the baseline:
Form1.cs:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 frm = new Form2();
frm.Button1Click += (s1, e1) => Lbl.Text = ((Form2)s1).Message;
frm.Show();
}
}
The above code creates a new instance of Form2, and then before showing it, adds an event handler to that form's Button1Click event.
Note that the expression (s1, e1) => Lbl.Text = ((Form2)s1).Message is converted automatically by the compiler to a method that looks something similar to (but definitely not exactly like) this:
private void frm_Message(object s1, EventArgs e1)
{
Lbl.Text = ((Form2)s1).Message;
}
There are actually lots of ways/syntaxes to implement and subscribe the event handler. For example, using an anonymous method as the above, you don't really need to cast the sender parameter; instead you can just use the frm local variable directly: (s1, e1) => Lbl.Text = frm.Message.
Going the other way, you don't need to use an anonymous method. You could in fact just declare a regular method just like the compiler-generated one I show above, and then subscribe that method to the event: frm.Button1Click += frm_Message; (where you have of course used the name frm_Message for the method, just as in my example above).
Regardless of how you do it, of course you will need for Form2 to actually implement that Button1Click event. That's very simple…
Form2.cs:
public partial class Form2 : Form
{
public event EventHandler Button1Click;
public string Message { get { return txtMessage.Text; } }
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
EventHandler handler = Button1Click;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
In addition to the event, I've also declared a property Message that exposes the Text property (and only the Text property, and only as read-only in fact) of the txtMessage control. This allows the subscriber to the event to get the value and do whatever it needs to with it.
Note that all that the event does is to alert the subscriber that the button has in fact been clicked. It's up to the subscriber to decide how to interpret or react to that event (e.g. by retrieving the value of the Message property and assigning it to something).
Alternatively, you could in fact deliver the text along with the event itself, by declaring a new EventArgs sub-class and using that for the event instead:
public class MessageEventArgs : EventArgs
{
public string Message { get; private set; }
public MessageEventArgs(string message)
{
Message = message;
}
}
public partial class Form2 : Form
{
public event EventHandler<MessageEventArgs> Button1Click;
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
EventHandler handler = Button1Click;
if (handler != null)
{
handler(this, new MessageEventArgs(txtMessage.Text));
}
}
}
Then the subscriber can just retrieve the message value directly from the event object:
frm.Button1Click += (sender, e) => Lbl.Text = e.Message;
The important thing note in all of the above variations is that at no point does the class Form2 need to know anything about Form1. Having Form1 know about Form2 is unavoidable; after all, that's the object that will create a new Form2 instance and use it. But the relationship can be asymmetrical, with Form2 being usable by any object that needs the features it offers. By exposing the functionality as an event (and optionally with a property), it makes itself useful without limiting its usefulness to only the Form1 class.
The best in this case would be to have some OptionsService class/interface that is accessible via IServiceProvider.
Just add an event when something changes, and the rest of the app can respond to it.
There are lots of ways to perform communication between two Forms.
Some of them have already been explained to you. I am showing you the other way around.
Assuming you have to update some settings from the child form to the parent form. You can make use of these two ways as well :
Using System.Action (Here you simply pass the main forms function as the parameter to the child form like a callback function)
OpenForms Method ( You directly call one of your open forms)
Using System.Action
You can think of it as a callback function passed to the child form.
// -------- IN THE MAIN FORM --------
// CALLING THE CHILD FORM IN YOUR CODE LOOKS LIKE THIS
Options frmOptions = new Options(UpdateSettings);
frmOptions.Show();
// YOUR FUNCTION IN THE MAIN FORM TO BE EXECUTED
public void UpdateSettings(string data)
{
// DO YOUR STUFF HERE
}
// -------- IN THE CHILD FORM --------
Action<string> UpdateSettings = null;
// IN THE CHILD FORMS CONSTRUCTOR
public Options(Action<string> UpdateSettings)
{
InitializeComponent();
this.UpdateSettings = UpdateSettings;
}
private void btnUpdate_Click(object sender, EventArgs e)
{
// CALLING THE CALLBACK FUNCTION
if (UpdateSettings != null)
UpdateSettings("some data");
}
OpenForms Method
This method is easy (2 lines). But only works with forms that are open.
All you need to do is add these two lines where ever you want to pass some data.
Main frmMain = (Main)Application.OpenForms["Main"];
frmMain.UpdateSettings("Some data");
Properties is one option, shared static class - another option, events - another option...
You might try AutoMapper. Keep your options in a separate class and then use AutoMapper to shuttle the data between the class and the form.
Create a Class and put all your properties inside the class .. Create a Property in the parent class and set it from your child (options) form
You can have a function in Form B like so:
public SettingsResults GetNewSettings()
{
if(this.ShowDialog() == DialogResult.Ok)
{
return new SettingsResult { ... };
}
else
{
return null;
}
}
And you can call it like this:
...
using(var fb = new FormB())
{
var s = fb.GetNewSettings();
...
// Notify other parts of the application that settings have changed.
}
MVC, MVP, MVVM -- slight overkill for someone admittedly saying they want tutorials. Those are theories that have entire courses dedicated to them.
As already posted, passing an object around is probably easiest. If treating a class as an object (interchangeable in this sense) is new, then you may want to spend another 2-4 weeks figuring out properties and constructors and such.
I'm not a C# master by any means, but these concepts need to be pretty concrete if you want to go much further beyond passing values between two forms (also classes/objects in their own right). Not trying to be mean here at all, it just sounds like you're moving from something like VB6 (or any language with globals) to something far more structured.
Eventually, it will click.
This is probably sidestepping your problem a little bit, but my settings dialog uses the Application Settings construct. http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx
I can't find a good example that's similar to how I do it (which is actually having an actual class+object), but this covers another way of doing it:
Reading default application settings in C#
A form is a class, just like any other class. Add some public variables to your form class and set them when they click the button to close the form (technically they are just hiding it).
A VB.NET example, but you'll get the idea -
In your OptionsForm class:
Public Option1 as String = ""
etc. Set them when they hit the "Ok" button.
So in your main form, when they hit the "options" button - you create your options form:
OptionsForm.ShowDialog()
when it exits, you harvest your option settings from the public variables on the form:
option1 = OptionsForm.Option1
etc.
The best way to deal with communication between containers is to implement an observer class
The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.
(Wikipedia)
the way i do this is creating an Observer class, and inside it write something like this:
1 public delegate void dlFuncToBeImplemented(string signal);
2 public static event dlFuncToBeImplemented OnFuncToBeImplemented;
3 public static void FuncToBeImplemented(string signal)
4 {
5 OnFuncToBeImplemented(signal);
6 }
so basically: the first line says that there would be a function that somebody else will implement
the second line is creating an event that occurs when the delegated function will call
and the third line is the creation of the function that calls the event
so in your UserControl, you should add a function like this:
private void ObserverRegister()//will contain all observer function registration
{
Observer.OnFuncToBeImplemented += Observer_OnFuncToBeImplemented;
/*and more observer function registration............*/
}
void Observer_OnFuncToBeImplemented(string signal)//the function that will occur when FuncToBeImplemented(signal) will call
{
MessageBox.Show("Signal "+signal+" received!", "Atention!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
and in your Form you should do something like:
public static int signal = 0;
public void button1_Click(object sender, EventArgs e)
{
Observer.FuncToBeImplemented(signal);//will call the event in the user control
}
and now, you can register this function to a whole bunch of other controls and containers and they will all get the signal
I hope this would help :)
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?!
I have 2 windows Forms, a parent and a child. The parent is the main form. The child is a dialog where the user can edit their details.
When a button is clicked on the parent form, it loads the child form. Like so:
private void add_account_Click(object sender, EventArgs e)
{
this.account_add_edit = new Form2();
account_add_edit.test();
account_add_edit.ShowDialog();
}
As you can see I've created a new form, tried to call a function from the new form, and then showed the form. The problem is the method from the form is not being called. I am getting an error on the IDE that says Windows.Forms.Form does not contain a method test.
I've created the method in the child form:
public static string test(string val)
{
this.username = val;
}
Any ideas as to what I'm doing wrong?
your method is defined as static , so its not posiible to call it on an instace.
you should eaither not make it static, or call it from as static:
Form2.test();
Use:
Form2.test();
static members are associated directly to the class not to its instances. Than means if you need to access a static member you have to access it using it is container type.
More than that, you can not access normal members from static ones. You can only access staticmembers from their peers.
You cannot do the following inside a static method:
this.Member ...
How can I Handle MDIParent Form events in childs forms?
for example in Parent Form I Have a option "search on child grid" and when that button got clicked, in the child form one row on grid get focused.
Im using C# 3.5 Windows Forms Application
Thanks in Advance
I see two different way that I would choose between for this problem.
If you could think of hosting the command in a MenuStrip instead, and it is the same child form that lives in several instances in the MDI application, you could add the command(s) to a MenuStrip control in the child form instead. These menu commands will be automatically merged with the commands in the parent form, but any click events will be carried out in the active child form.
You can control where and how menu commands from the child form merges with the commands in the parent form through the MergeAction and MergeIndex properties. If using this approach you should probably set the Visible property of the MenuStrip in the child form to false to prevent it from taking up unnecessary space on the form.
The second option that I would suggest is to create an interface for defining the search functionality, implement that interface in the child forms that support it, and use the MdiChildActivate event of the MDI parent form to enable or disable the search function based on whether the current child supports it or not.
Simplified code sample of the second approach:
interface IGridSearch
{
void PerformSearch(string criteria);
}
public partial class MdiChildUI : Form, IGridSearch
{
public MdiChildUI()
{
InitializeComponent();
}
public void PerformSearch(string criteria)
{
// peform the search
}
}
public partial class MdiParentUI : Form
{
public MdiParentUI()
{
InitializeComponent();
}
private void MdiParentUI_MdiChildActivate(object sender, EventArgs e)
{
SetControlStates();
}
private void SetControlStates()
{
_searchCommand.Enabled = (this.ActiveMdiChild is IGridSearch);
}
private void _searchCommand_Click(object sender, EventArgs e)
{
IGridSearch child = (this.ActiveMdiChild as IGridSearch);
if (child != null)
{
child.PerformSearch("whatever to search for");
}
else
{
MessageBox.Show("Can't search in the active form");
}
}
}
It's not too complicated:
public partial class Form1 : Form
{
// other stuff...
// e.g. some button's click event handler
private void addChild_Click(object sender, EventArgs e)
{
Form2 child = new Form2();
child.MdiParent = this;
this.SomeEvent += child.SomeMethod();
// other init stuff...
}
}
Just make sure the signature of the handler method on the child Forms matches the signature of the event handler delegate of the parent.
One thing to note is if you want only the active child form to respond to the event. In that case you can create a helper extension method like this
public static bool IsActiveMDIChild(this Form child)
{
Form mdiParent = Form.ActiveForm;
Form activeChild = mdiParent.ActiveMdiChild;
return child == activeChild;
}
Then add code like this to the SomeMethod() handler:
public bool SomeMethod(*/ signature here /*)
{
if(!this.IsActiveMDIChild()) return;
//do stuff normally, we're in the active child form
}
In the child form, create a new event for the parent to call:
Friend Event search(ByVal token As String)
In the parent form, declare an instance of the child form withevents:
Private WithEvents _FChild As frmChild
In the parent form, when you want to call the child form, reference your declared variable. The event should appear in intellisense:
Private Sub searchChild_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSearchChild.Click
_FChild.search(txtToken)
Have you some code so we can be more helpful?
In any case, you can create your custom events on the child forms, and get the Parent form to suscribe to these events
I'm doing the same kind of thing right now, and here's how I do it:
Since the parent is the one raising the event, the event needs to exist on the parent form
During the code on the parent that loads the child (you have code somewhere that instantiates the child form), after the child form exists, use AddHandler to tether the event on the MDI parent with a public sub on the child form
When the parent form fires the event, the instance of the child form will handle it.
Does this make sense? I'm using VB.NET, so the language may be slightly different, but that's the general technique I'm using.