This question already has answers here:
Communicate between two windows forms in C#
(12 answers)
Closed 6 years ago.
hey everyone I am currently trying to refresh a form once changes are done on a second. On my first form I press a button "create" that will open another form, form2. This second form will have input fields and allows you to input values that populate comboboxes on the first form. On the second form there is a button "update" I would like the fist form to refresh once update is pressed on the first.
I know there is this.refresh();, but I'm not sure if this is useful for me. I am trying to something along the lines of:
On form2 -
Private void Form2UpdateButton_Click
{
//do update stuff
Form1_load.Refresh();
}
or maybe
private void Form2UpdateButton_Click
{
//do update stuff
Form1.close();
Form1.Open();
}
I am still pretty new to C# and interacting 2 forms together is a rather complex concept to me so please let me know if I am going about this the wrong way. My refresh may be in the wrong spot, but I think this is what I want.
Create an own event on form2 that triggers when the button gets clicked. This way you can just form2.OnUpdateClicked += yourMethod. Like this:
public partial class Form1 : Form
{
private void CreateForm2()
{
Form2 frm2 = new Form2();
// Hook the event of form2 to a method
frm2.PropertyUpdated += Form2Updated;
}
private void Form2Updated(object sender, EventArgs e)
{
// this will be fired
}
}
public partial class Form2 : Form
{
// On form2 create an event
public event EventHandler PropertyUpdated;
private void Form2UpdateButton_Click()
{
// If not null (e.g. it is hooked somewhere -> raise the event
if(PropertyUpdated != null)
PropertyUpdated(this, null);
}
}
Recommendations:
Your second form should be created with a reference to first one, ie,
Form1:
public void RefreshParameters()
{
// ... do your update magic here
}
private void openForm2(..)
{
// Pass your current form instance (this) to new form2
var aForm = new Form2(this);
aForm.Show(); // show, run, I don't remember... you have it
}
Form2:
// Here you will store a reference to your form1
form1 daddy = null;
// A new constructor overloading default one to pass form1
public Fomr2(Form1 frm):base()
{
daddy = frm; // Here you store a reference to form1!
}
public void UpdateDaddy()
{
// And here you can call any public function on form1!
frm.RefreshParameters();
}
One way is to pass a reference of Form1 to Form2, like this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void buttonLaunchForm_Click(object sender, EventArgs e)
{
Form2 form2 = new Form2();
form2.LauncherForm = this;
form2.Show();
}
public void RefreshFormData()
{
// Refresh
}
}
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
public Form1 LauncherForm { set; get; }
private void buttonUpdate_Click(object sender, EventArgs e)
{
// do your normal work then:
LauncherForm.RefreshFormData();
}
}
The above technique is called "Property-Injection";
Related
I hope the title is clear enough. Let me explain : I am doing a c# Winform App. When I start the app I have my Form 1 which starts, and I have other forms I can open from it by clicking buttons.
The problem is, I have functions in those Forms (Form 2, Form 3, Form 4..) I want to start from the Form 1 .
Currently here's my code
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// First Event, when I click in the toolstrip menu, I open the Form2 ("Ligne3")
private void ligne3ToolStripMenuItem_Click(object sender, EventArgs e)
{
var Ligne3 = new Ligne3();
Ligne3.Show();
}
Then, I have components in the Form2 (textboxs, buttons, functions etc)
public partial class Ligne3 : Form
{
public Ligne3()
{
InitializeComponent();
}
private void Ligne3_Load(object sender, EventArgs e)
{
//Some code
}
}
//Function I want to call from the Form1
public void send_email()
{
//Some code
}
How can I start my " send_email() " function from the Form1 (for example during Load Event) ?
Assign the values of Form2 or any other objects/variables to Linge3 object before calling show. Values which are needed in send_email() to be assigned before calling send_email(). Something like below.
private void ligne3ToolStripMenuItem_Click(object sender, EventArgs e)
{
var ligne3 = new Ligne3();
//define variables/properties in Ligne3 for all values to be passed
//then assign them with corresponding values
ligne3.Value1 = objForm2.Value1;
ligne3.Value2 = objForm2.Value2;
ligne3.Value3 = objForm2.textBox1.Text;
ligne3.Value3 = objForm2.checkBox1.Value;
//and so on
ligne3.send_email();
ligne3.Show();
}
If you are clicking a buttons on Form1, to start and open forms 2,3,4 etc, and in those btn_click handlers you are creating a new form2, 3,3,4. Then you will have a reference to each form and and can therefore just call the respective public method on the instance just created. eg
public class Form1
{
private Form2 subForm2;
private void OpenForm2_Click(object sender, eventargs e)
{
subForm2 = new Form2();
subForm2.Show()
}
private void sendEmailBtn_Click(object sender, EventArgs e)
{
subForm2.Send_email();
}
}
This are many things wrong with the above from a design point of view but i'm just using it to present the idea.
If you are creating the instance of Form2,3,4 etc outside of Form1's instantiation, then you would need some form of Constructor or property injection to provide the instance references.
I am new to c#. I have the following in my project in windows forms:
Form1 with button and DataGridView.
Form2 with button.
Form3 with button and 3 textBoxes.
As shown in the screenshot In form1, I click buttonOpenForm2 form2 pops up. Then in form2 I click buttonOpenForm3 form3 pops up which has 3 text boxes and button. Now the 3 forms are open.
I enter values in textBox1, textBox2 and textBox3 and when click buttonAddRow ( from form3) I want these values to be inserted into the DataGRidView in Form1.
My question is:
How can I add a row into DataGridView in Form1 ( parent) from form3 (child of child form) WITHOUT closing form2 and form3? I mean I want to pass the data while form2 and form3 are still open.
Please help me. Thank you
Form1:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void buttonOpenForm2 _Click(object sender, EventArgs e)
{
Form2 frm2 = new Form2();
frm2.Show();
}
}
Form2:
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void buttonOpenForm3 _Click(object sender, EventArgs e)
{
Form3 frm3 = new Form3();
frm3.Show();
}
}
Form3:
public partial class Form3 : Form
{
public Form3()
{
InitializeComponent();
}
private void buttonAddRow _Click(object sender, EventArgs e)
{
//What to write here to insert the 3 textboxes values into DataGridView?
}
}
You cannot expect to get complete code that's ready to be pasted. I quickly wrote this in notepad to give you idea about how events work best in such cases. I assumed Form1 directly opens Form3. Solution below shows how to use events.
You home work is to make it work by adding another form Form2 in between. You can do so by propagating same event via Form2 which sits in middle.
Form3.cs
public partial class Form3 : Form
{
public event EventHandler<AddRecordEventArgs> RecordAdded
public Form3()
{
InitializeComponent();
}
private void buttonAddRow _Click(object sender, EventArgs e)
{
OnRecordAdded();
}
private void OnRecordAdded() {
var handler = RecordAdded;
if(RecordAdded != null) {
RecordAdded.Invoke(this, new AddRecordEventArgs(txtQty.Text, txtDesc.Text, txtPrice.Text))
}
}
}
AddRecordEventArgs.cs
public class AddRecordEventArgs : EventArgs
{
public AddRecordEventArgs(string qty, string desc, string price) {
Quantity = qty;
Description = desc;
Price = price;
}
public int Quantity { get; private set; }
public string Description { get; private set; }
public decimal Price { get; private set; }
}
Form1.cs
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void buttonOpenForm3_Click(object sender, EventArgs e)
{
Form3 frm3 = new Form3();
frm3.RecordAdded += Form3_RecordAdded;
frm3.Show();
}
private void Form3_RecordAdded(object sender, AddRecordEventArgs e) {
// Access e.Quantity, e.Description and e.Price
// and add new row in grid using these values.
}
}
1 Solution
You can use pattern with sending data further by constructor (special setter before Show method) and getting them back after window is closed by public getter.
public partial class Form2 : Form
{
Data Data1 {get; set;}
//Instead of Data you can pass Form1 class as parametr.
//But this might lead to unreadable code, and using too mutch methods and fields that could be private, public
public Form2(Data data)
{
InitializeComponent();
Data1 = data;
}
private void buttonOpenForm3 _Click(object sender, EventArgs e)
{
//Repeat pattern
Form3 frm3 = new Form3(Data1);
frm3.Show();
}
}
Optionally you dont have to call 3rd window constuctor. Just create Instance of third window store it in first form and just Show it by calling first instance you passed with data. But this might be bad practice in larger scale.
2 Solution
You can use singleton pattern. Create Instance of an first form inside constructor of first form and use it in third form. But you would need to ensure that there will be no more then one and always one instance of this object in memory.
You can pass owner to method Show() for new forms. Then you can get owner form from Owner property.
private void buttonOpenForm2 _Click(object sender, EventArgs e)
{
Form2 frm2 = new Form2();
frm2.Show(this);
}
So you can get Form1:
(Form1)frm2.Owner
and call public method of Form1 class and pass there your new data.
I am trying to add a new item to a listbox in form1 from form2. The idea behind it is to end up with a list of different items each being different from each other (or the same, doesnt matter) based on the form2 activity. Say I open form1 (and it has shopping list (listbox))and I open form2 and click button which would add "bannana" to the list in form1. How do I do this? I've tryed various ways such as adding "addToList(parameter)" method in the form1 and then calling it from form2 and passing parameters but the list would remain empty however other things such as message box would pop up etc. So any ideas how to solve this?
I am using this method in form one to add the items into the list and it works:
public void addToList()
{
MessageBox.Show("Adding stuff to list");
listEvent.Items.Add("New item 1");
listEvent.Items.Add("new item 2");
MessageBox.Show("Done adding");
listEvent.Refresh();
}
Now when I try to call it from another class/form I use this:
public void changeForm()
{
EventPlanner mainEventForm = new EventPlanner();
mainEventForm.addToList();
}
Or:
private void btnAddEvent_Click(object sender, EventArgs e)
{
EventPlanner mainEventForm = new EventPlanner();
mainEventForm.addToList();
}
But it still doesnt work. Although when I use it from form1 (eventplanner, where the list is) it works perfectly fine. I even changed access modifyer to public so that shouldnt be the problem.
You can use a public Method on Form2 as I mentioned in my comment to your question. Here is a simple example.
Form1
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 frm2 = new Form2();
if (frm2.ShowDialog(this) == DialogResult.OK)
{
listBox1.Items.Add(frm2.getItem());
}
frm2.Close();
frm2.Dispose();
}
}
From2
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
button1.DialogResult = DialogResult.OK;
button2.DialogResult = DialogResult.Cancel;
}
public string getItem()
{
return textBox1.Text;
}
}
I am passing data between 2 windows forms in c#. Form1 is the main form, whose textbox will receive the text passed to it from form2_textbox & display it in its textbox (form1_textbox).
First, form1 opens, with an empty textbox and a button, on clicking on the form1_button, form2 opens.
In Form2, I entered a text in form2_textbox & then clicked the button (form2_button).ON click event of this button, it will send the text to form1's textbox & form1 will come in focus with its empty form1_textbox with a text received from form2.
I am using properties to implement this task.
FORM2.CS
public partial class Form2 : Form
{
//declare event in form 2
public event EventHandler SomeTextInSomeFormChanged;
public Form2()
{
InitializeComponent();
}
public string get_text_for_Form1
{
get { return form2_textBox1.Text; }
}
//On the button click event of form2, the text from form2 will be send to form1:
public void button1_Click(object sender, EventArgs e)
{
Form1 f1 = new Form1();
f1.set_text_in_Form1 = get_text_for_Form1;
//if subscribers exists
if(SomeTextInSomeFormChanged != null)
{
SomeTextInSomeFormChanged(this, null);
}
}
}
FORM1.CS
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public string set_text_in_Form1
{
set { form1_textBox1.Text = value; }
}
private void form1_button1_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2();
f2.Show();
f2.SomeTextInSomeFormChanged +=new EventHandler(f2_SomeTextInSomeFormChanged);
}
//in form 1 subcribe to event
Form2 form2 = new Form2();
public void f2_SomeTextInSomeFormChanged(object sender, EventArgs e)
{
this.Focus();
}
}
Now, in this case I have to again SHOW the form1 in order to automatically get the text in its textbox from form2, but I want that as I click the button on form2, the text is sent from Form2 to Form1, & the form1 comes in focus, with its textbox containing the text received from Form2.
I know this is a (really) old question, but hell..
The "best" solution for this is to have a "data" class that will handle holding whatever you need to pass across:
class Session
{
public Session()
{
//Init Vars here
}
public string foo {get; set;}
}
Then have a background "controller" class that can handle calling, showing/hiding forms (etc..)
class Controller
{
private Session m_Session;
public Controller(Session session, Form firstform)
{
m_Session = session;
ShowForm(firstform);
}
private ShowForm(Form firstform)
{
/*Yes, I'm implying that you also keep a reference to "Session"
* within each form, on construction.*/
Form currentform = firstform(m_Session);
DialogResult currentresult = currentform.ShowDialog();
//....
//Logic+Loops that handle calling forms and their behaviours..
}
}
And obviously, in your form, you can have a very simple click listener that's like..
//...
m_Session.foo = textbox.Text;
this.DialogResult = DialogResult.OK;
this.Close();
//...
Then, when you have your magical amazing forms, they can pass things between each other using the session object. If you want to have concurrent access, you might want to set up a mutex or semaphore depending on your needs (which you can also store a reference to within Session). There's also no reason why you cannot have similar controller logic within a parent dialog to control its children (and don't forget, DialogResult is great for simple forms)
I have two Form classes, one of which has a ListBox. I need a setter for the SelectedIndex property of the ListBox, which I want to call from the second Form.
At the moment I am doing the following:
Form 1
public int MyListBoxSelectedIndex
{
set { lsbMyList.SelectedIndex = value; }
}
Form 2
private ControlForm mainForm; // form 1
public AddNewObjForm()
{
InitializeComponent();
mainForm = new ControlForm();
}
public void SomeMethod()
{
mainForm.MyListBoxSelectedIndex = -1;
}
Is this the best way to do this?
Making them Singleton is not a completely bad idea, but personally I would not prefer to do it that way. I'd rather pass the reference of one to another form. Here's an example.
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)
Access the form's controls like this:
formname.controls[Index]
You can cast as appropriate control type, Example:
DataGridView dgv = (DataGridView) formname.Controls[Index];
I usually use the Singleton Design Pattern for something like this http://en.wikipedia.org/wiki/Singleton_pattern . I'll make the main form that the application is running under the singleton, and then create accessors to forms and controls I want to touch in other areas. The other forms can then either get a pointer to the control they want to modify, or the data in the main part of the application they wish to change.
Another approach is to setup events on the different forms for communicating, and use the main form as a hub of sorts to pass the event messages from one form to another within the application.
It's easy, first you can access the other form like this:
(let's say your other form is Form2)
//in Form 1
Form2 F2 = new Form2();
foreach (Control c in F2.Controls)
if(c.Name == "TextBox1")
c.Text = "hello from Form1";
That's it, you just write in TextBox1 in Form2 from Form1.
If ChildForm wants to access the ParentForm
Pass ParentForm instance to the ChildForm constructor.
public partial class ParentForm: Form
{
public ParentForm()
{
InitializeComponent();
}
public string ParentProperty{get;set;}
private void CreateChild()
{
var childForm = new ChildForm(this);
childForm.Show();
}
}
public partial class ChildForm : Form
{
private ParentForm parentForm;
public ChildForm(ParentForm parent)
{
InitializeComponent();
parentForm = parent;
parentForm.ParentProperty = "Value from Child";
}
}
There is one more way, in case you don't want to loop through "ALL" controls like Joe Dabones suggested.
Make a function in Form2 and call it from Form1.
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
public void SetIndex(int value)
{
lsbMyList.SelectedIndex = value;
}
}
public partial class Form1 : Form
{
public Form2 frm;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
frm=new Form2();
frm.Show();
}
private void button1_Click(object sender, EventArgs e)
{
frm.SetIndex(Int.Parse(textBox1.Text));
}
}
Here's also another example that does "Find and Highlight". There's a second form (a modal) that opens and contains a textbox to enter some text and then our program finds and highlights the searched text in the RichTextBox (in the calling form). In order to select the RichTextBox element in the calling form, we can use the .Controls.OfType<T>() method:
private void findHltBtn_Click(object sender, EventArgs e)
{
var StrBox = _callingForm.Controls.OfType<RichTextBox>().First(ctrl => ctrl.Name == "richTextBox1");
StrBox.SelectionBackColor = Color.White;
var SearchStr = findTxtBox.Text;
int SearchStrLoc = StrBox.Find(SearchStr);
StrBox.Select(SearchStrLoc, SearchStr.Length);
StrBox.SelectionBackColor = Color.Yellow;
}
Also in the same class (modal's form), to access the calling form use the technique mentioned in the #CuiousGeek's answer:
public partial class FindHltModalForm : Form
{
private Form2 _callingForm = null;
public FindHltModalForm()
{
InitializeComponent();
}
public FindHltModalForm(Form2 CallingForm)
{
_callingForm = CallingForm;
InitializeComponent();
}
//...