My application reads an array from another system and this
array is holding data that is updated every second using a
timer in the Parent form.
The Parent form has a textbox and a button to open a new
Child Form. When the button is pressed the Child Form is
opened and displays a live value according to the index which
was entered in the text box of the Parent Form.
I have this working fine with the live value being
continually updated on the Child Form using parameters (ie
the Get & Set commands in the Child Form).
My problem is that I want to open multiple Child Forms that
can each display a different live value and be updated every
second.
When I open the second (or third, fourth etc ) Child Form I
have the problem that only the last Child Form opened is
updated with live values. The Child Forms that were opened
before, just show the last values and are not updated.
Can anyone point me in the right direction to get the live
values to update on each Child Form...
I have not copied in my code as have played around with it
quite a lot and would need to clean it up before presenting
to everyone. I was looking for a point in the right direction
rather than being spoon fed code. If needed, I can post the
code...
Many thanks in advance
Loading
Sam HobbsPosted May 10, 2011, 12:35 AM
Since Frogleg did not explain what his code does, I don't know if I have an alternative. It sure would help if I had a general idea at least of what it shows.
Without spending a lot of time with the details, my initial idea would be to create a method in the child form class and also somewhere in your program keep an array or list of all child forms. Then when the data is updated, iterate through the list of child forms and call the update method in the child form. I am assuming that each child form knows what index to use in the data to get it's updated data. Would that satisfy the requirements?
MontePosted Jun 23, 2011, 10:34 AM
MontePosted Jun 23, 2011, 10:31 AM
Sam HobbsPosted Jun 22, 2011, 4:32 PM
MontePosted Jun 22, 2011, 4:09 PM
I posted another topic on this and have now resolved the issue - see my other post on this:
http://www.c-sharpcorner.com/Forums/Thread/127395/problem-with-closed-event-of-a-child-form.aspx
Basically I had to comment out the bit of code which deletes the closed event handler. Looks like VS2003 gets confused if you try and delete the event handler...
Anyway all working now.
VulpesPosted Jun 1, 2011, 4:21 AM
child.Closed -= this.Child_Closed;
wasn't introduced until .NET 2.0. Amazing how quickly you forget!
MontePosted Jun 1, 2011, 2:18 AM
Have got it working OK now. My problem was with getting the event handler to work OK so had to use the following code to make it work. I'm not nitpicking just including the code so others in the future can see what worked. It is due to using an old version of software - Visual Studio 2003.
private void ChildForm_Closed(object sender, EventArgs e)
{
Form2 child = (form2)sender;
this.child.Closed -= new EventHandler(this.child_Closed);
childList.Remove(child);
}
Thanks also Max for the input - I need to brush up on Delegates and give this a go as a learning exercise.
Max CervantesPosted May 27, 2011, 9:09 PM
VulpesPosted May 25, 2011, 12:52 PM
Before that, you had to use the Form.Closed event which is still there though deprecated in later versions.
The revised code will be:
MontePosted May 25, 2011, 12:27 PM
I am wondering if this wasnt available in VS 2003?
The project is the same as described in this post ie one parent form with a button that will open multiple instances of a child form. I am using an arraylist to keep tabs on which Child Forms are open which works fine. The problem is when I close a Child Form, I want to be able to delete it from the Array list in the Parent.
If the .FormClosed event does not work in VS2003 then any other ideas how to recognise a child form is closed and delete it from the arraylist in the parent?
Thanks in advance...
Max CervantesPosted May 17, 2011, 9:24 AM
if not clear enough, just google for "observer pattern"
MontePosted May 12, 2011, 4:10 PM
I have changed over to ArrayLists and it works fine (as before) but without the need to specify a max number of child forms - hence the code should be more efficient on memory.
Thanks also to Max for the info on Delegates. Yes I went down this route before and got the data exchange to work to the most recent child form opened only. I will have a play with Delegates using your information and try to get the updates to work across all child forms...
Many thanks again for the info.
Max CervantesPosted May 12, 2011, 10:02 AM
Delegate void updateData(Array data);
Then u set an event in ur parent form.
event updateData OnUpdate.
Next u need to create a method that conforms to the delegate signature in every child form. I would create a base form that implements it, and then just subclass it.
class baseForm:Form{
....
public virtual void DataUpdate(Array data){}
}
Now u just need to override the method in every form and select the data u want that form to display. Or u could use a single form, and just pass the constructor the index parameter, like this:
class ChildForm: Form{
int index;
public ChildForm(int DataToDisplayIndex){
index = DataToDisplayIndex;
}
public void DataUpdate(Array data){
this.textbox1.text = data[index].ToString();
}
}
Next u should subscribe to the parent form event, like this:
ChildForm child = new ChildForm(selectedDataIndex);
OnUpdate += child.DataUpdate;
After that it's just a matter of firing the event every time u receive new data:
Array data = getNewestData();
if(OnUpdate != null){
OnUpdate.Invoke(data);
}
and presto! ur childForms will update automatically.
don't forget to adda an event handler to the child form FormClosed event. Just like vulped explained before.
...
child.FormClosed += this.Child_FormClosed;
...
private void ChildForm_FormClosed(object sender, FormClosedEventArgs e)
{
ChildForm child = (ChildForm)sender;
child.FormClosed -= this.Child_FormClosed;
OnUpdate-= child.DataUpdate;
}
Hope this help ya, this was my first post ever! ;)
Greetings from mexico!
VulpesPosted May 11, 2011, 5:40 PM
The cast is necessary because the ArrayList stores everything internally as type object.
Mahesh ChandPosted May 11, 2011, 4:03 PM
Cheers!
MontePosted May 11, 2011, 4:01 PM
I have got it working doing what Sam suggested by way of creating an array of Forms and an array of index numbers. When a new Child form is requested to be opened then a copy is saved in the array of forms along with the index in the array of indexes.
When a timer counts down then the parameters in each Child form are updated by looping through the array of forms and updating values using the array of indexes and using properties (get/set) to update fields.
The only negative is that I have to define the array of forms to be a fixed number of forms long. Hence (in my unexperienced mind) it is not very efficient in memory and there is a max number of forms that can be opened.
I didnt use the MDI method as I didnt understand that so well. When I get spare time I will read up on MDI and have a play.
I have uploaded the final (ish) project so anyone else trying to do the same thing in the future can see what I did. It is a Visual Studio 2003 project and gets information from another system called IMACS - so you may need to comment out the references to this to get it to compile.
No exception handling has been added yet.
Thanks again for all the help - maybe one day I will be able to help others and return the favour.
FroglegPosted May 11, 2011, 12:13 AM
Just post any questions
Sam HobbsPosted May 10, 2011, 3:10 PM
Note that there is not a button labeled "third" in the parent; at least I don't see it. Do you mean bttnSend?
I will attempt to describe what I suggest.
First note that you are using MDI. Your main form is a MDI container and the child forms have the parent as a MDI parent. Many developers think that MDI means multiple windows but it means multiple documents with a window for each document. In your application, you do have data that is unique to each child so that means you are using MDI appropriately. To use MDI in the manner it was intended to be used, it would be more appropriate for the data to be in objects separate from the main form but that is a relatively minor detail. If however your actual requirements are for more than one item to be shown in the child forms then perhaps it would be better to not put the data in the main form.
I think that .Net control classes are designed well in the manner that there is a lot of flexibility in the objects that can be used for the items that controls provide a UI for. So what that means for you is that you can create a class for objects of the combobox control. You can create instances of that class and add them to the combobox. One member of the class can be a reference to a child form. So then when a combobox item is selected, the item will know what child form to update, without doing a lookup. When the update button is clicked, the button handler will get the item selected in the comboboxand then just use the child form reference in the object.
The problem is that I am not sure that is relevant to your final solution. I get the impression that your prototype solution is not relevant to your actual requirements.
VulpesPosted May 10, 2011, 2:20 PM
As Sam said earlier, you need to create a list of child forms opened. You'll also need to keep track of any closures. I don't know whether they are all instances of Form2 but I'll assume for now they are:
private List
private void button3_Click(object sender, System.EventArgs e)
{
Form2 child = new Form2();
child.ValueFromParent= this.masterTextBox.Text;
child.FormClosed += this.Child_FormClosed;
child.Show();
childList.Add(child);
}
// add this handler manually
private void ChildForm_FormClosed(object sender, FormClosedEventArgs e)
{
Form2 child = (Form2)sender;
child.FormClosed -= this.Child_FormClosed;
childList.Remove(child);
}
When you update the textboxes on each form, you'll then need to use code such as this:
foreach(Form2 child in childList)
{
child.ValueFromParent = "whatever";
}
MontePosted May 10, 2011, 1:42 PM
I am still wondering if there is a simple solution- as a relative newcomer to C# I figured there was something that I was missing like a tick box to say keep all ChildForms live etc etc.
Thanks for your thoughts as well Sam - I am not using MDI Child forms.
I can see that I should have added my code so people can see what I mean. I have created a simple project with two forms - Parent and Child. Forgetting Arrays of data that I mentioned before, all I want to be able to do is keep creating Child Forms by event button3_Click.
Then when I change data in a textbox in the Parent Form I want this change to be seen in the single textboxes on all the Child Forms. At present only the last ChildForm that I opened will be updated.
Once I get this working then I can use the method on the proper project using arrays of data and a single data item to be passed to each child form using a timer.
I am assuming that there is a simple fix due to something that I dont know about in C#. I have looked at lots of forums on this but struggle to see an answer to this particular problem.
I have also uploaded the file - which is in Visual Studio 2003 - the button labelled "third" on the parent, is the one that I am interested in. The others are just other things that I have tried such as Delegates.
Many Thanks again in advance.
*****************************
*****PARENT FORM**************
*****NB Some code stripped out****
*****************************
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace FormToForm
{
///
/// Summary description for Form1.
///
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
public System.Windows.Forms.TextBox masterTextBox;
///
/// Required designer variable.
///
private System.ComponentModel.Container components = null;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.Button button4;
private System.Timers.Timer timer1;
//Added manually for the comms to work
public Form2 ChildForm;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
///
/// The main entry point for the application.
///
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void button3_Click(object sender, System.EventArgs e)
{
this.ChildForm = new Form2();
this.ChildForm.ValueFromParent= this.masterTextBox.Text;
this.ChildForm.Show();
}
private void masterTextBox_TextChanged_1(object sender, System.EventArgs e)
{
if (this.ChildForm !=null)
this.ChildForm.ValueFromParent = this.masterTextBox.Text;
}
}
}
******************************
*****CHILD FORM****************
*****NB Some code stripped out*****
******************************
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
namespace FormToForm
{
///
/// Summary description for Form2.
///
public class Form2 : System.Windows.Forms.Form
{
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Button button1;
public System.Windows.Forms.TextBox secondaryTextBox;
///
/// Required designer variable.
///
private System.ComponentModel.Container components = null;
public Form2(string initialValue)
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
ValueFromParent = initialValue;
//
// TODO: Add any constructor code after InitializeComponent call
//
}
public Form2()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
public string ValueFromParent
{
set
{
this.secondaryTextBox.Text = value;
}
}
}
}
FroglegPosted May 9, 2011, 3:14 PM