Changing the label of from2 from within the function of form1 - c#

Ok, so I have Form1 calling Form2 in a way that allows me to access Form1's functions from Form2. Code Below...
Form1....
private void btnShowForm2_Click(object sender, EventArgs e)
{
frmForm2 tempDialog = new frmForm2(this);
tempDialog.ShowDialog();
}
Form2...
private frmForm1 _parent;
public frmForm2(frmForm1 frm1)
{
InitializeComponent();
_parent = frm1;
}
private void btnDoFunction_Click(object sender, EventArgs e)
{
_parent.DoProcess();
}
Now I have a new problem. I'm trying to update a status label of Form2, but the function that's processing the task at hand is in Form1. How can I change the label of Form2 from within the Function of Form1?

You can do so using delegate and event.
Make an event in form1 using a delegate
On progress in form1's process trigger the event.
put a handler to the form1 event in form2.
Extract the progress from that eventargs implemented object in the handler.
Show it in the lable in form2

This is a mess... form1 displays form2 which calls a method on form1 which updates the contents form2? Your question itself is easy (move the tempDialog variable to the form1 class instead of within this method - then you can use this during DoProcess to tweak whatever controls you want) but there is a serious maintainability problem here that you should step back and try to address.

If you really want to access frm2.lbl from frm1 then frm2.lbl must be public, this can be changed in the properties window of the label on Form2. (under modifiers I think)
private void btnDoFunction_Click(object sender, EventArgs e)
{
_parent.DoProcess();
}
(in form1)
public void DoProcess();
{
tempDialog.lable.Text = "hope this works";
}

Related

Detect when a child form is closed

I have he following Form:
An Initialize Function that is called when the Form1 is created.
A button that opens another Form (Form2)
What I need is to call Initialize() not only when Form1 is created, but whenever Form2 is closed, since Form2 might have modified some stuff that makes Initialize need to be called again.
How can I detect when the form2 is closed?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Initialize();
}
void Initialize()
{
// Read a config file and initialize some stuff
}
// Clicking this button will open a Form2
private void button1_Click(object sender, EventArgs e)
{
var form2 = new Form2().Show();
}
}
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
// some stuff that Form2 does which involves modifying the config file
}
}
You just need to add an event handler for the FormClosing event, this handler could be in your first form class and here you can call every internal method of that class
private void button1_Click(object sender, EventArgs e)
{
var form2 = new Form2();
form2.FormClosing += childClosing;
form2.Show();
}
private void childClosing(object sender, FormClosingEventArgs e)
{
Initialize();
....
}
In addition to Steve's excellent answer, you may consider displaying Form2 as a modal dialog. This would mean code execution in Form1 STOPS until Form2 is dismissed. This may or may not work well with your application, we have no idea what it does.
At any rate, you'd use ShowDialog() instead of Show() like this:
// Clicking this button will open a Form2
private void button1_Click(object sender, EventArgs e)
{
var form2 = new Form2().ShowDialog(); // <-- code STOPS here until form2 is closed
Initialize(); // form2 was closed, update everything
}

Accessing button from another form

I have 2 forms each with buttons, textboxes, and labels. In form1 I have a this code in a button event handler:
frmTwo form = new frmTwo ();
form.Show();
this.Visible = false; //closing form 1 when frmTwo opens
I went to the designer file for frmTwo and changed all of the controls: labels, textboxes, buttons from private (which was auto generated) to public.
Under this line of code: this.Visible = false; I want to put an if statement to check if a name textbox in frmTwo is blank. But when I write txtName.Text it says the textbox doesn't exist in the current context. I understand why it doesn't exist because its inside frmTwo NOT from1. But I'm not sure what other ways I can access this textbox because I already made it public in the designer. Is there another way to do this?
Ask yourself: Is it important for form1 that the information that you want to read from form2 is in a textbox? Would form1 really care if the same information would be kept by form2 in a ComboBox?
Wouldn't it be best if form1 doesn't know how form2 gets the information? All it has to know is that form2 is willing to provide the information. If form2 needs to read it from a database, or fetch it from the internet to fetch the information, why would form1 care? All form1 wants to know: "Hey Form2, give me information X"
Alas you didn't tell us if you want this information only once, or that form1 needs to be kept informed whenever information X changes. Let's assume that you do.
So, class Form2 will have a method to provide information X, and it is willing to tell everyone that information X is changed. Form2 does not show to the outside world how it gets its information. The current version holds information X in the text of TextBox1. Future versions might read it from a ComboBox, or read if from a file, or from the internet.
class Form2 : System.Windows.Window
{
public event EventHandler XChanged;
public string X
{
// information X is in textBox1
get => this.textBox1.Text;
}
private void TextBox1_Changed(object sender, ...)
{
// the text in textBox1 changed, so information X changed
this.OnXChanged();
}
protected virtual void OnXChanged()
{
this.XChanged?.Invoke(new Eventhandler(this, EventArgs.Empty));
}
... // other Form2 methods
}
Now if Form1 wants to know the value of X, it can simply ask for it:
Form2 form2 = ...
string informationX = form2.X;
If Form1 wants to be kept informed whenever information X changes:
form2.XChanged += InformationXChanged;
private void InformationXChanged(object sender, Eventargs e)
{
Form2 form2 = (Form2)sender;
// get the new information X from form2:
string informationX = form2.X;
this.ProcessInformationX(informationX);
}
If you want one form to replace the other, then you pass a reference to Form1 in the .Show() of Form2 and the form stores it in the .Owner property. The when the second form starts it will hide the first form. Additionally, when the second form closes it can unhide the first form.
Please use Capitalized names for types like Form and pascalCase for variables like mainForm = new Form().
Form1.cs
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var f2 = new Form2();
f2.Show(this);
}
}
Form2.cs
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.FormClosing += Form2_FormClosing;
this.Owner.Visible = false;
}
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
Owner.Visible = true;
}
public bool IsNameBlank { get => string.IsNullOrWhiteSpace(textBox1.Text); }
}
This is the basic framework. I also added some logic where Form1 checks for a textBox in Form2. Add a property in Form2 that returns the check:
and access it form From1
private void button1_Click(object sender, EventArgs e)
{
var f2 = new Form2();
f2.Show(this);
if (f2.IsNameBlank)
{
// textBox is empty.
}
}

Remove last item in datagridview with another form C# [duplicate]

I have two forms. First, Form1 has a group box, some labels and a listbox. I press a button and new Form2 is opened and contains some text. I want to transfer the text in Form2 to the listbox in the Form1.
So far, what I have done is make modifier of listbox to public and then put this code in the button of Form2
Form1 frm = new Form1();
frm.ListBox.items.Add(textBox.Text);
But amazingly, this does not add any value. I thought I was mistaken with the insertion so I made the same procedure. This time, I made a label public and added textbox value to its Text property but it failed.
Any ideas?
Try adding a parameter to the constructor of the second form (in your example, Form1) and passing the value that way. Once InitializeComponent() is called you can then add the parameter to the listbox as a choice.
public Form1(String customItem)
{
InitializeComponent();
this.myListBox.Items.Add(customItem);
}
// In the original form's code:
Form1 frm = new Form1(this.textBox.Text);
Let's assume Form1 calls Form2. Please look at the code:
Form1:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 frm = new Form2();
frm.Show();
frm.VisibleChanged += formVisibleChanged;
}
private void formVisibleChanged(object sender, EventArgs e)
{
Form2 frm = (Form2)sender;
if (!frm.Visible)
{
this.listBox1.Items.Add(frm.ReturnText);
frm.Dispose();
}
}
}
Form2:
public partial class Form2 : Form
{
public string ReturnText { get; set; }
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
this.ReturnText = this.textBox1.Text;
this.Visible = false;
}
}
The answer is to declare public property on Form2 and when form gets hidden. Access the same instance and retrieve the value.
Below code working perfect on my machine.
private void button1_Click(object sender, EventArgs e)
{
Form1 f1 = new Form1();
f1.listBox1.Items.Add(textBox1.Text );//ListBox1 : Modifier property made public
f1.ShowDialog();
}
Ok, If you are Calling Sequence is like, Form1->Form2 and Form2 updates the value of Form1 then you have to use ParentForm() or Delegate to update the previous form.
Form1 frm = new Form1();
frm is now a new instance of class Form1.
frm does not refer to the original instance of Form1 that was displayed to the user.
One solution is, when creating the instance of Form2, pass it a reference to your current instance of Form1.
Please avoid the concept of making any public members like you said
>>i have done is make modifier of listbox to public and then in form2 in button code<<
this is not a good practice,on the other hand the good one is in Brad Christie's Post,I hope you got it.
This code will be inside the form containing myListBox probably inside a button click handler.
Form2 frm2 = new Form2();
frm2.ShowDialog();
this.myListBox.Items.Add(frm2.myTextBox.Text);
frm2.Dispose();

Refreshing/Reload From form 1 to form 2

private void Form1_Load(object sender, EventArgs e)
{
f2 = new Form2();
f2.Show();
}
I have that code on my Form1. So that will automatically run Form2_Load. Is it possible that when I click a button on Form1. Form2_Load will run again without having to close Form2.
In response to your comment:
When a button on Form1 is clicked it will send a message update to form2. And a textbox in Form2 will have the message.
(First of all, this isn't the Observer Pattern. But that's ok, it doesn't need to be.)
First, Form1 needs to retain its reference to the instance of Form2:
public class Form1
{
private Form2 Form2Instance { get; set; }
private void Form1_Load(object sender, EventArgs e)
{
Form2Instance = new Form2();
Form2Instance.Show();
}
// the rest of your code
}
Now other code on Form1 can reference that instance. This is because you don't want to actually reload all of Form2 any time anything changes. You just want to "send a message update to form2".
Now, how will Form2 receive that message? It can expose a method. Something like this:
public class Form2
{
public void Update(string newValue)
{
someTextBox.Text = newValue;
}
// the rest of the code
}
Now code on Form1 can call that method on the instance of Form2 that it references. So when you click a button on Form1, you might do this:
Form2Instance.Update("some value");
This would "send a message" to the instance of Form2.

How to refresh datagridview when closing child form?

I've a dgv on my main form, there is a button that opens up another form to insert some data into the datasource bounded to the dgv. I want when child form closes the dgv auto refresh. I tried to add this in child form closing event, but it doesn't refresh:
private void frmNew_FormClosing(object sender, FormClosingEventArgs e)
{
frmMain frmm = new frmMain();
frmm.itemCategoryBindingSource.EndEdit();
frmm.itemsTableAdapter.Fill(myDatabaseDataSet.Items);
frmm.dataGridView1.Refresh();
}
However, when I add this code in a button on the parent form, it actually does the trick:
this.itemCategoryBindingSource.EndEdit();
this.itemsTableAdapter.Fill(myDatabaseDataSet.Items);
this.dataGridView1.Refresh();
There are many ways to do this, but the following is the simpliest and it will do what you want and get you started.
Create a public method on your main form.
Modified constructor of second form to take a main form.
Create an instance of the second form passing the main form object.
When closing second form, call the public method of the main form object.
Form1
public partial class Form1 : Form {
public Form1() {
//'add a label and a buttom to form
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e) {
Form2 oForm = new Form2(this);
oForm.Show();
}
public void PerformRefresh() {
this.label1.Text = DateTime.Now.ToLongTimeString();
}
}
Form2
public class Form2 : Form {
Form1 _owner;
public Form2(Form1 owner) {
_owner = owner;
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form2_FormClosing);
}
private void Form2_FormClosing(object sender, FormClosingEventArgs e) {
_owner.PerformRefresh();
}
}
We can also proceed this way:
We have form_1 and form_2
In form_1, create a public method. Inside this public method we put our stuff;
In form_2 we create a global form variable;
Still in form_2, pass form_1 into form_2 through form_2 constructor;
Still in form_2, make your global variable(the one we created in step 2) receive the new form_1 instance we created in form_2 constructor;
Inside the closing_event method we call the method which contains our stuff.
The method with our stuff is the method that will fill our form1 list, dataGridView, comboBox or whatever we want.
Form_1:
public fillComboBox()//Step 1. This is the method with your stuff in Form1
{
foreach(var item in collection myInfo)
{myComboBox.Items.Add(item)}
}
Form_2:
Form1 instanceForm1;//Step 2
public Form2(Form1 theTransporter)//Step 3. This the Form2 contructor.
{
InitializeComponent();
instanceForm1 = theTransporter;//Step 4
}
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
instanceForm1.fillComboBox();//Step 5 we call the method to execute the task updating the form1
}
I hope it helps...
You're creating a new instance of the main form which isn't effecting the actual main form instance. What you need to do is, call the code on the main form itself, just like the code you say works on the button click:
private void frmNew_FormClosing(object sender, FormClosingEventArgs e)
{
this.itemCategoryBindingSource.EndEdit();
this.itemsTableAdapter.Fill(myDatabaseDataSet.Items);
this.dataGridView1.Refresh();
}
Great answer there! The other method would have been:
Check if the form you want to update is open.
Call the method to refresh your gridVieW.
**inside your refreshMethod() in form1 make sure you set the datasource to null **
if (System.Windows.Forms.Application.OpenForms["Form1"]!=null)
{
(System.Windows.Forms.Application.OpenForms["Form1"] as Form1).refreshGridView("");
}

Categories