Related
This may sound stupid, But I am having hard time to figure this out; any help would be appreciated:
I have two user controls called “Safety_Check” and “OEE_Track”. In my MainForm I have a panel called “pnl_main_controller” this is where I am displaying both my user controls. I have two buttons on my main form and I am dynamically switching between both without any issue.
Safety_Check User control;
public partial class Safety_Check : UserControl
{
private static Safety_Check _instance;
public static Safety_Check instance
{
get
{
if (_instance == null)
_instance = new Safety_Check();
return _instance;
}
}
public Safety_Check()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
///////------------------------
}
}
OEE_Track User control
public partial class OEE_Track : UserControl
{
private static OEE_Track _instance;
public static OEE_Track instance
{
get
{
if (_instance == null)
_instance = new OEE_Track();
return _instance;
}
}
public OEE_Track()
{
InitializeComponent();
}
}
MainForm:
public partial class MainForm : Form
{
private void btn_reg_Click(object sender, EventArgs e)
{
if (!pnl_main_controller.Contains(Safety_Check.instance))
{
pnl_main_controller.Controls.Add(Safety_Check.instance);
Safety_Check.instance.Dock = DockStyle.Fill;
Safety_Check.instance.BringToFront();
}
else
{
Safety_Check.instance.BringToFront();
} }
private void btn_OEE_Click(object sender, EventArgs e)
{
if (!pnl_main_controller.Contains(OEE_Track.instance))
{
pnl_main_controller.Controls.Add(OEE_Track.instance);
OEE_Track.instance.Dock = DockStyle.Fill;
OEE_Track.instance.BringToFront();
}
else
{
OEE_Track.instance.BringToFront();
}
}
What I am trying to do is I have a button called “Button1” on my “Safety_Check” Usercontrol, whenever I press this , I want “Safety_Check” to be disappear on “pnl_main_controller” and bring “OEE_Track” to the panel
There are several solutions for interaction between controls. Controls are classes and like any other class they can interact with each other using their public properties and methods or using some mediator.
In this case, your controls don't need to know each other and don't need to interact to each other directly:
They can ask another object which knows both controls, to do the job for them.
Or they can raise their request notification and the one who subscribed to that notification, will serve it.
To ask another object to do the job for them you have multiple solutions. As an example you can implement a specific interface in the parent form and in the child controls, cast the parent to that specific interface and call a specific method which do the job for you.
For raising the request notification, an easy solution is relying on events. You can create an event in the child control and raise it when you need the parent do something for you. Then in the parent subscribe to that event and do the job.
Example - Using event
I assume you have UserControl1 having Button1 inside and you have handled Click event of Button1. Then you can create Button1Clicked event and raise it when Button1 clicked:
public event EventHandler Button1Clicked;
private void Button1_Click(object sender, EventArgs e)
{
Button1Clicked?.Invoke(this, e);
}
Then in the parent form, subscribe for the event and do whatever you want:
private void userControl11_Button1Clicked(object sender, EventArgs e)
{
//Hide userControl11 and show userControl21
}
Example - Using interface
I assume, you have an interface having a few standard methods:
public interface IDoSomething
{
void DoSomething();
void DoSomethingElse();
}
And you have implemented the interface in your parent form:
public class Form1: Form, IDoSomething
{
// ...
public void DoSomething()
{
//Hide userControl11 and show userControl21
}
public void DoSomethingElse()
{
// ...
}
}
Then in you user control:
private void Button1_Click(object sender, EventArgs e)
{
var f = FindForm() as IDoSomething;
if(f!=null)
f.DoSomething();
}
I want to expand on Reza Aghaei's answer a bit. I think it could get even better than it is now.
First way to do this
If I were you I would have some interface ICheckedView which has at least 1 method to implement like so:
ICheckedView
{
void Continue();
}
Now, we're able to apply this interface to any class in our solution, most likely to views, though. Next, I would make your main form implement this interface and implement the required method. The in this case we want our main form to remove the control from the panel and add a new control. Frankly, our Safety check control doesn't need to (and maybe shouldn't) know about other controls or what happens next. It's just used for flow of control.
Finally, you need to add either a public property, or maybe even a parameter to the constructor for Safety_Check which includes an ICheckedView in it. When your safety check control gets clicked it can tell whoever has been passed into it (we'll say the client) that it must continue.
Second way to do this
It can be done with an action delegate.
If you add an Action delegate to your safety check, you could just pop in any method whose signature matches that delegate (void methodName()). The constructor for your Safety_Check control should include an Action and that Action would get assigned to a private field of the class. Then when it's time to invoke, that action can be invoked directly.
Notes on this method
Because we're probably invoking from the UI thread in the first place, we're probably alright, but you need to think about thread safety here. The invoke required pattern can help you around this.
I have a Main form, Form A, Form B and Form C which all include comboboxes. I want the selection in Form A or B or C to display on a text box or a label on the Main form. How do I do that? I would like to do this without buttons. Just selecting an item from the drop down menu and displaying it on the Main form.
Please help!!!
Many thanks in advance!
Your problem essentially boils down to doing something on one form based on the events of another form.
The best approach to do this is, in my opinion:
Let Main do all its own actions.
Let FormA (and others) do all its own actions.
If you need to do something on Main based on an event that occurred on FormA, let FormA notify Main that something happened there, so go do your own thing.
If necessary, pass data from FormA to Main.
So I would make use of delegates for this purpose.
In my Main I'd declare a public delegate with a signature like this:
public delegate void NotifyComboBoxChange(string item);
That is, this delegate represents a method that takes in one string parameter, and has void return type. The idea is to let FormA 'call' a method in Main, and that method essentially notifies the combo box item was changed on FormA. So, if there was a way for us to call a method that resides in the Main from FormA, we can then notify Main of an event happening on FormA With me so far?
Now, if I write a method like this in the Main, and let it be called from FormA, that should accomplish our goal. Here, txtLabel is a TextBlock in Main.
public void ComboBoxValueChanged(string value)
{
txtLabel.Text = value;
}
To call such a method, I would define a delegate of type NotifyComboBoxChange in Main like below, and register the ComboBoxValueChanged() method to it. Your Main code behind should look like this:
public delegate void NotifyComboBoxChange(string item);
public partial class Form1 : Window
{
public NotifyComboBoxChange notifyDelegate;
FormA formA = null;
public Form1()
{
InitializeComponent();
// This is 'registering' the ComboBoxValueChanged method to the delegate.
// So, when the delegate is invoked (called), this method gets executed.
notifyDelegate += new NotifyComboBoxChange(ComboBoxValueChanged);
}
public void ComboBoxValueChanged(string value)
{
txtLabel.Text = value;
}
private void btnOpen_Click(object sender, RoutedEventArgs e)
{
// Passing the delegate to `FormA`
formA = new FormA(notifyDelegate);
formA.Show();
}
}
Accordingly, now we need to modify our FormA. We need to tell us which delegate to invoke when the combo box selection change happens. So to do that, I'd pass the delegate in the constructor of FormA like so:
public partial class FormA : Window
{
NotifyComboBoxChange notifyDel;
public FormA(NotifyComboBoxChange notify)
{
InitializeComponent();
notifyDel = notify;
}
private void cmbItems_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// This gets the currently selected value in the CombBox
var value = cmbItems.SelectedValue.ToString();
// This invokes the delegate, which in turn calls the ComboBoxValueChanged() method in Main.
notifyDel?.Invoke(value);
}
}
Set your main form Control property of Modifier to public or inherit your
own choice from the control window property.
Pass the Main-form object (this) to FormA,FormB,FormC when you are showing
them.Now I'm showing them on button click.
private void showingAllForm_Click(object sender, EventArgs e)
{
FormA a = new FormA(this);
a.Show();
FormB b = new FormB(this);
b.Show();
FormC c = new FormC(this);
c.Show();
this.IsMdiContainer = true;
a.MdiParent = this;
c.MdiParent = this;
b.MdiParent = this;
}
Setting Constructor for FormA,FormB,FormC and add Combobox on FormA,FormB,FormC so to add following code for each combobox such as
FormA Replace for FormB,FormC and so on.
public partial class FormA : Form
{
public FormA()
{
InitializeComponent();
}
MainForm fm;
public FormA(MainForm fm)
{
InitializeComponent();
this.fm = fm;
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
fm.textBox1.Text = comboBox1.Text;
}
}
Output Results
I know that VS will open an eventhandler stub by doubleclicking on an event.
I found the underlying event declaration in InitializeComponent of the form on which the button is located.
this.buttonWorkOn.Click += new System.EventHandler(this.buttonWorkOn_Click);
Can I use this event declaration (of Visual Studio) and register another eventhandling method with it?
Upon instantiation of that other form its eventhandling method would need to register itself with the click event of the button on the main form.
I have no clue how to do that even though I have read quite a bit about delegates and events and in principle I do understand how it works.
Thank you
If you right click on an event handler in the code editor and browse the definition you will find the way that it is declared, which you can then use in your own code.
For example, the declaration for a Button's Click event is:
public event EventHandler Click;
You can add these yourself and use them from other places to respond to events in any class you create.
Here's a sample form with a single button (added via the designer) that when clicked will raise its own event:
public partial class Form1 : Form
{
public event EventHandler ButtonClicked;
private void RaiseButtonClicked()
{
if (ButtonClicked != null)
ButtonClicked(this, EventArgs.Empty);
}
public Form1()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
RaiseButtonClicked();
}
}
In another class you can then add a handler to that:
public class Responder
{
public Responder(Form1 form)
{
form.ButtonClicked += OnButtonClicked;
}
private void OnButtonClicked(object sender, EventArgs args)
{
MessageBox.Show("Button was clicked");
}
}
Now every instance of the Responder class will tell you when the button is clicked on the form.
By "Double clicking on an event", visual studio will generate an event handler for you. What you don't see is that visual studio also subscribes the generated event handler to the event, by adding a line of code in your designer file.
If goes something like this:
Double click 'clicked' event
Visual studio opens up your code file, and you have a new button1_clicked method, which is your event handler.
Your designer is updated with a line like button1.Clicked += button1_clicked
If you want to do manual event subscriptions, you can do so from your code file, by adding something like <formelement>.<event> += <eventhandler>. If you cant see available events in your intellisense, you can always check the online documentation. MSDN
(You should never change your designer file, as this is a generated file)
If you like to get multiple methods been executed when an event occurs you can simply add all of them in your code (or you can even add the same method multiple times):
private void DoSomething(object source, EventArgs eventArgs)
{
Console.WriteLine("Something happened.");
}
private void DoSomethingElse(object source, EventArgs eventArgs)
{
Console.WriteLine("Something else happened.");
}
private void AttachToEvent()
{
button1.Clicked += DoSomething;
button1.Clicked += DoSomethingElse;
button1.Clicked += DoSomething;
}
This would print out:
Something happened.
Something else happened.
Something happened.
OK – it was not my application, I just tried to improve on it.
Anyway, the question was who owns whom and who is visible where.
On the Mainform are controls for user input.
On MainForm a variable of type "class preview" is declared:
Preview pv
For the Preview class I added an event declaration named WorkOn:
public class Preview
{
#region "Variables"
#region "PublicEvent"
public event EventHandler WorkOn;
}
Then in the MainForm, the variable pv – declared as a class field - is instantiated within a method.
pv = new Preview()
after which the user input in the controls of the main form is checked and when ok saved in the variables of the preview class.
Then, the PreviewForm is instantiated within the preview class, with the instance of the owning class (preview --> as instance pv) passed as a variable to the instantiation of the PreviewForm.
I had to create this overloaded constructor because from the PreviewForm an eventhandler must be registered with the preview class to make this work – as I realized.
formPreview formPreview = new formPreview(this);
// this --> is the class preview, the instance pv
// Instantiation of FormPreview
public formPreview(Preview preview)
{
InitializeComponent();
this.preview = preview;
// now for the event in the preview class an eventhandling method
// of the preview form is registered:
preview.WorkOn += formPreview_Close;
}
This is the registered method of FormPreview:
private void formPreview_Close(object sender, EventArgs e)
{
this.Close();
}
I was reminded again that events can only be raised from the class that publishes the event. So I had to create a public event raising method within the class preview – here named OnWorkOn:
public void OnWorkOn()
{
if (WorkOn != null)
WorkOn(this, EventArgs.Empty);
}
And finally I could trigger the event from the MainForm within the button to whose underlying event I planned to register the eventhandling method of the PreviewForm in the first place.
Only now I had to use the class variable pv of the MainForm as it is the medium between the MainForm and the PreviewForm:
public void buttonWorkOn_Click(object sender, EventArgs e)
{
pv.OnWorkOn();
// raising the event, informing whoever is registered to it
//...
}
So the design of the application did not allow for registering any eventhandling method of the preview form directly on the MainForm. That was the problem and I didn't quite see through the whole design yet.
Well – this is the outcome of a german C# tutorial – the only german one I know of.
You'll find it here:
[https://www.youtube.com/watch?v=-zCiwcgxMHw&list=PLvvL1HRuCBItyw45XnCqEXzuegKQd3MfL][1]
The code is not available for download anymore, but I could provide it as I am through.
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 :)