I am working on a game that utilizes Windows Forms in C#. I want to be able to use the first form to call a second form. I have this working. Then I would like for the second form to send data back to the first form rather than creating a new instance of the first form. Can this be done? I know I need to have my properties set up so that I can set the variables from one form to the other. I am just not sure how to go about calling the first form without creating a new instance of it.
Is there a way that this can be done?
For example if I have Form A create an instance of Form B, can I have Form B do some work and send the data back to the original Form A without creating a new instance of Form A?
If you don't use the Data sent back Form A right away then you could use the Form_Closing event handler Form B and then a public property in Form B also.
In your Form A it could look like this:
public partial class FormA : Form
{
FormB frmB = new FormB(); // Instantiate FormB so that you could create an event handler in the constructor
public FormA()
{
InitializeComponent();
// Event Handler for Form Closing
frmB.FormClosing += new FormClosingEventHandler(frmB_FormClosing);
}
void frmB_FormClosing(object sender, FormClosingEventArgs e)
{
String fromFormB = frm2.FormBData; // Get Data from Form B when form is about to close
}
private void button1_Click(object sender, EventArgs e)
{
frmB.ShowDialog(); // Showing Form B
}
}
And in your Form B it could look like this:
private void button1_Click(object sender, EventArgs e)
{
// Let just say that the data is sent back once you click a button
FormBData = "Hello World!";
Close();
}
public String FormBData { get; set; }
It's hard to say without knowing your full requirements. But generally I go like this (Somewhat psuedo code).
Form2 dialogForm = new Form2();
if(dialogForm.ShowDialog() == DialogResult.OK)
{
this.PropertyOnForm1 = dialogForm.PropertyOnForm2
}
This ofcourse relies that your second form is a dialog. You will need to set the dialogresult buttons on Form2, and have a public property that will be accessed from Form1 once the dialog has been completed.
Let me know if this doesn't work and I'll write up a different answer.
Since you are creating Form2 in Form1, you can create a custom event in Form2 and subscribe to it in Form1 at the time that you create Form2, if you are returning information from Form2 when you are closing it then Edper's or MindingData's answers will work.
Here is a quick and dirty example using EventHandler<TEventArgs>
Form1
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 frm2 = new Form2();
frm2.myCustomEvent += frm2_myCustomEvent;
frm2.Show();
}
void frm2_myCustomEvent(object sender, string e)
{
this.Text = e;
}
}
Form2
public partial class Form2 : Form
{
public event EventHandler<string> myCustomEvent;
int count;
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
count +=1;
myCustomEvent(sender, count.ToString());
}
}
Related
This is a demo example, I can't use the original code. This context is very simplified.
I want to call a button/event from the child form (form2) when I'm clicking a button from the mother form (form1). I want to do this via subscribing (which I don't really understard since I'm new to coding).
Mother form:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 f = new Form2();
f.Show();
//Call the Button from Form2 here
}
}
Child Form:
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("MessageBox called from Form1 or Form2");
}
}
What you want to do, the way you want to do it, is in general not a good idea as you should not be relying on UI controls on another from, from your other form.
What you can do to achieve what you asked for without rewriting anything is more like this:
1) in the button click of Form2, you do not do anything else than calling a method on Form2, event handler contains no other logic
2) you make that method of form2 public
3) from your button click on form1, you call that same public method of form2
again, this would work but it is not necessarily the best design, it really depends on the whole architecture of your app if this fits or not with the rest or there are better and different ways to accomplish this.
Don't call other form "button clicks", if you want to call some logic from different places, extract logic into dedicated class and call it from both places
public class MyLogic
{
public void Execute(string someParameter)
{
// Do something with parameter
}
}
Then use it in both forms
public partial class Form1 : Form
{
private readonly MyLogic _importantLogic;
public Form1()
{
InitializeComponent();
_importantLogic = new MyLogic();
}
private void button1_Click(object sender, EventArgs e)
{
_importantLogic.Execute(this.textBox1.Text);
}
}
public partial class Form2 : Form
{
private readonly MyLogic _importantLogic;
public Form2()
{
InitializeComponent();
_importantLogic = new MyLogic();
}
private void button1_Click(object sender, EventArgs e)
{
_importantLogic.Execute("Always Form 2");
}
}
I try to update Form1 values from Form2, but nothing happens. No errors also, strange...
Form1:
public static Form2 f2{ get; set; } = new Form2();
private void addButton1_Click(object sender, EventArgs e)
{
f2.Show();
}
Form2:
public void button1_Click(object sender, EventArgs e)
{
Form f1 = new Form();
f1.label2.ForeColor = Color.Red;
}
Nothing happens. I can get data to my form2 from form1, but I cannot send, I mean I can, but nothing happens... Why? Thank you
The other solutions mentioned here would work for your specific case, but I encourage you to look at the big picture, and design a generalized solution that will work for most cases.
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 Form1 do all its own actions.
Let Form2 do all its own actions.
If you need to do something on Form1 based on an event that occurred on Form2, let Form2 notify Form1 that something happened there, so go do your own thing.
If necessary, pass data from Form2 to Form1.
So I would make use of delegates for this purpose.
Imagine you have a Button and a Label on your Form1. Clicking the button opens up Form2, on which you have another Button. Clicking this button on Form2 should change the background color of the label on Form1. So our setup would look like this. You haven't mentioned if it's Winforms or WPF, so I'm using WPF for my convenience but the idea is the same in either.
Form1
Form2
In my Form1 I'd declare a public delegate with a signature like this:
public delegate void NotifyEvent();
That is, this delegate represents a method that takes in no parameters, and has void return type. The idea is to let Form2 'call' a method in Form1, and that method essentially notifies the button was clicked on Form2. So, if there was a way for us to call a method that resides in the Form1 from Form2, we can then notify Form1 of an event happening on Form2 With me so far?
Now, if I write a method like this in the Form1, and let it be called from Form2, that should accomplish our goal. Here, lblDisp is the Label in Form1.
public void ButtonClickedOnForm2()
{
lblDisp.Background = new SolidColorBrush(Colors.LawnGreen);
}
To accomplish this, I would define a delegate of type NotifyEvent in Form1 like below, and register the ButtonClickedOnForm2() method to it. Your Form1 code behind should look like this
public delegate void NotifyEvent();
public partial class Form1 : Window
{
public NotifyEvent notifyDelegate;
Form2 form2 = null;
public Form1()
{
InitializeComponent();
// This is 'registering' the ButtonClickedOnForm2 method to the delegate.
// So, when the delegate is invoked (called), this method gets executed.
notifyDelegate += new NotifyEvent(ButtonClickedOnForm2);
}
public void ButtonClickedOnForm2()
{
lblDisp.Background = new SolidColorBrush(Colors.LawnGreen);
}
private void BtnOpen_Click(object sender, RoutedEventArgs e)
{
// Passing the delegate to `Form2`
form2 = new Form2(notifyDelegate);
form2.Show();
}
}
Accordingly, now we need to modify our Form2. We need to tell us which delegate to invoke when the button click happens. So to do that, I'd pass the delegate in the constructor of Form2 like so:
public partial class Form2 : Window
{
NotifyEvent notifyDel;
public Form2(NotifyEvent notify)
{
InitializeComponent();
notifyDel = notify;
}
private void BtnOK_Click(object sender, RoutedEventArgs e)
{
// This invokes the delegate, which in turn calls the ButtonClickedOnForm2 method in Form1.
notifyDel.Invoke();
}
}
Now, when the button is clicked on Form2, it invokes the delegate. And on our Form1, we've told it that in case the delegate is invoked, it should go ahead and execute the ButtonClickedOnForm2 method. In that method, we've written code to change the background color of the label. And that should solve your problem.
Passing Data
Additionally, if you want to pass data from Form2 to Form1, you can simply add parameters to the delegate definition. Say you want to pass a string from Form2 to Form1. Then, you'd change your delegate to look like this:
public delegate void NotifyEvent(string data);
And the method ButtonClickedOnForm2 like so:
public void ButtonClickedOnForm2(string data)
{
lblDisp.Content = data;
lblDisp.Background = new SolidColorBrush(Colors.LawnGreen);
}
Then on Form2, invoke the delegate by passing a string like so:
private void BtnOK_Click(object sender, RoutedEventArgs e)
{
// This invokes the delegate, which in turn calls the ButtonClickedOnForm2 method in Form1.
notifyDel.Invoke("I am from Form2");
}
Now clicking the button on Form2 should change text and background color of label on Form1 like this:
With Form f1 = new Form(); you are creating a new form instead of accessing one which is already open and you don't call f1.Show(); therefore it will never be displayed. You need a reference to the one which is open. E.g. pass form 1 as constructor parameter to form 2.
In form 2:
public partial class Form2 : Form
{
private readonly Form1 _form1;
public Form2 (Form1 from1)
{
_form1 = form1;
InitializeComponent();
}
public void button1_Click(object sender, EventArgs e)
{
_form1.label2.ForeColor = Color.Red;
}
}
In form 1:
// Cannot be static as we need a reference to `this`
private Form2 _f2;
public Form2 f2 {
get {
if (_f2 == null) {
_f2 = new Form2(this); // Pass form 1 as parameter to form 2.
}
return _f2;
}
}
private void addButton1_Click(object sender, EventArgs e)
{
f2.Show();
}
Thank you for constructor idea. Anyway (this) does not work for me in global scope. So I needed to simplify it to this:
Form 2 with constructor:
public Form1 _form1 { get; set; }
public Form2(Form1 form1)
{
_form1 = form1;
InitializeComponent();
}
public void button1_Click(object sender, EventArgs e)
{
_form1.label2.ForeColor = Color.Red;
}
}
Form 1 creating new object with parameter everytime call needed(because of 'this'):
private void addButton1_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2(this);
f2.Show();
}
Works fine so far...
try this code
Form1:
private void addbutton1_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2(this);
f2.Show();
}
public void ColorChange()
{
label2.ForeColor = Color.Red;
}
Form2:
public Form1 f1;
public Form2(Form1 m)
{
this.f1 = m;
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
f1.Show();
f1.ColorChange();
}
Say, i have called a class in my mainform, like
BSPclass bsp = new BSPclass();
In that class there is 1 property like,
class BSPclass
{
public string p1 = "player1";
}
Then, if i click a button in mainform, a new form (as form2) will appear,
say, there is a textbox which will set a value for p1 (also BSPclass was called in form2 too)
private void save_Click(object sender, EventArgs e)
{
BSP.p1 = txtbox.text;
}
Now, problem is, if I close the form2, it doesn't show the neew value of p1 in mainform, still shows "player1"
How to refresh or do other anything?
It depends on where did you created BSP instance? If it's created in form2 then it's as well disposed along with the form. Both the instances are different here. You will have to pass it to main form using a delegate something like:
Say your main form have a insance of BSPclass like BSPclass bsp = new BSPclass();
In you form2 declare a delegate like
public delegate void passinfotomainform(string data);
Create a event of that delegate type
public event passinfotomainform datapassevent;
Then in button click raise the event
private void save_Click(object sender, EventArgs e)
{
BSP.p1 = txtbox.text;
if(datapassevent != null)
datapassevent(txtbox.text);
}
In main form, register this event like
form2.datapassevent += new EventHandler(myhandler);
In myhandler get the data
private void myhandler(string arg)
{
bsp.p1 = arg; //set the bsp in main form
}
You can simply pass the value of textbox to mainform and then refresh p1. You shouldn't create an instance of BSPClass in form2. See code below:
In form2:
public string pTemp;
private void save_Click(object sender, EventArgs e)
{
pTemp = txtbox.text;
}
In mainform:
BSPclass bsp = new BSPclass();
Form2 f=new Form2();
f.ShowDialog(this);
bsp.p=f.pTemp;
I have two forms, and I create the second by using:
Form2 f2 = new Form2();
f2.Show();
Form2 has a variable that is public and changes every mousemove. I have a button on that form which, when press, saves the variable. Now the problem is that I don't know how to pass it back to Form1.
You should use events. Form2 should define an event that is triggered as appropriate (it sounds like that should be when the button is clicked). Form1 can then subscribe to that event and do...whatever with it.
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
public event Action<string> MyEvent; //TODO give better name and set arguments for the Action
private void button1_Click(object sender, EventArgs e)
{
string someValue = "Hello World!"; //TODO get value that you want to share
if (MyEvent != null)
{
MyEvent(someValue);
}
}
}
And then in your main form:
private void button1_Click(object sender, EventArgs e)
{
Form2 otherForm = new Form2();
//subscribe to the event. You could use a real method here, rather than an anonymous one, but I prefer doing it this way.
otherForm.MyEvent += value =>
{
//do other stuff with "value".
label1.Text = value;
};
otherForm.Show();
}
I have 2 Forms. Form1 creates Form2 like this:
public partial class Form1 : Form
{
private void button3_Click(object sender, EventArgs e)
{
Form2 AcqForm = new Form2();
AcqForm.Show();
string[] ret = AcqForm.fulldate;
MessageBox.Show(ret[27]);
}
}
public partial class Form2 : Form
{
public string[] fulldate; //Created in form 2
close(); //Need to get this string back on or before close event
}
How should I go about doing this?
You need to handle the Form2 instance's FormClosed event in the first form and access the public properties.
Using this snippet, you can get a little knowledge on it.
in Form1:
using(Form2 form2 = new Form2())
{
if(form2.ShowDialog() == DialogResult.OK)
{
MessagBox.Show(form2.fulldate);
}
}
In Form2:
public partial class Form2 : Form
{
public string[] fulldate {get; set;} // Create a Property
void CloseForm()
{
fulldate = "valueToReturn";
DialogResult = DialogResult.OK;
}
}
Assuming you want button3_Click to wait until AcqForm is closed before accessing fulldate, you'll first have to change AcqForm.Show(); to AcqForm. ShowDialog();. (Show() doesn't wait for it to close.)
As for the fulldate field – it will be accessible even after the form closes because the form still exist. SLaks' remark about it being a 'field' means that we have different names for different types of 'variables'. What you have declared in the class (without get and set) is called a field. A variable in a method is called a 'variable'.
If you still want to do something when AcqForm closes, do this:
In Form1's constructor, before the AcqForm. ShowDialog();:
AcqForm.FormClosing += AcqForm_FormClosing;
And in Form1's class:
void AcqForm_FormClosing(object sender, FormClosingEventArgs e)
{
//Whatever will be here will be done when the form is closing.
//Use 'FormClosed' for doing things AFTER the form has closed.
}