3

i am using winforms with visual studio 2008.

i would to create an EXACT replica of my form with controls and all events, and all the same code as i have.

is this possible to do at runtime? how would i do it?

shouldnt there be some kind of class solution like:

Form form2 = new Form();
form2 = form1 ???
Azhar
  • 20,500
  • 38
  • 146
  • 211
Alex Gordon
  • 57,446
  • 287
  • 670
  • 1,062

2 Answers2

5

Just create another instance of the same class. Use the actual name of the class instead of the base class Form.

Form form2 = new Form1();
form2.Show();
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • @guffa how would i think run a method on that form? for example, if i want to trigger the click event on the new form2, how would i do it? – Alex Gordon Nov 05 '10 at 22:16
  • The new form2 itself would handle its own click events. If you wanted to fire a method on your new form2 from outside form2 itseld, make the method public (or internal, etc.) and fire it by calling form2.YourMethodName(). – Jay Riggs Nov 05 '10 at 22:29
  • @jay could you give me an example please – Alex Gordon Nov 05 '10 at 22:30
  • @jay how would i fill out a textbox on form2? – Alex Gordon Nov 05 '10 at 22:31
  • If you want to do this outside your form2, you can change the Modifiers property of your TextBox to public and then set your TextBox text by calling form2.YourTextBox.Text = "my text"; – Jay Riggs Nov 05 '10 at 22:35
  • @jay i guess that is the question, how would i change the modified for public programmtiaclly? – Alex Gordon Nov 05 '10 at 22:36
  • @i am a girl: Any control that you want to access from outside the form, you have to expose outside the class. Make it public (or internal), add a public propety that returns the control, or add a public method that does what you want. – Guffa Nov 05 '10 at 22:37
  • @guffa i am generating the new class during runtime, so how would i modify the controls to being public? is there any possibilitites? – Alex Gordon Nov 05 '10 at 22:38
  • Modifiers is a property of TextBox (and other controls). You can make this change in the WinForm designer. – Jay Riggs Nov 05 '10 at 22:38
  • @i am a girl: No, you are not generating a new class at runtime, you are only creating another instance of the same class. You can't change access modifiers at runtime. – Guffa Nov 05 '10 at 22:40
  • @guffa fine then how would a trigger a click event – Alex Gordon Nov 05 '10 at 22:48
1

Shooting from the hip, serialize the form and deserialize it into the second variable. : ) I'll try to look into this and come up with more of an answer.

Some things to watch out for... do you want a shallow or deep copy? I.E., if the form has a reference to an object, do you want to copy the reference (so both forms are pointing to the same object), or make a copy of that object, also? You have to be careful... there's no guarantee with objects that contain references to other objects which order they will be deserialized

You don't need to, but it's good practice to inherit from ICloneable, which has only one method, Clone(). Override this method with code similar to the following:

public object Clone() {

    BinaryFormatter formatter = new BinaryFormatter();
    MemoryStream stream = new MemoryStream();
    formatter.Serialize(stream, this);
    stream.Seek(0, SeekOrigin.Begin);

    return (MyForm) formatter.Deserialize(stream);

}

To use:

MyForm form2 = form1.Clone() as MyForm;
if (form2 != null) {
    // yahoo!
}

* Edit *
There's actually an excellent example here on SO that creates a generic object copier. Very nice!
Deep cloning objects


* Edit *
The problem with serializing the form is that not all the values can really be serialized... they make no sense, e.g. the handles on the individual controls.

To make the form serializable, you will need to implement the ISerializable interface, and implement the proper constructor and GetObjectData() method. In GetObjectData, you will need to enumerate your controls, and store the properties (e.g. Text or Value) that you want to copy. The constructor reads them back out. It looks like this:

public partial class MyForm : Form, ISerializable {

    public MyForm() {}

    public MyForm(SerializationInfo info, StreamingContext context) : base() {

        foreach (Control control in Controls) {
            control.Text = info.GetString(control.Name);
        }

    }

    public void GetObjectData(SerializationInfo info, StreamingContext context) {

        foreach (Control control in Controls) {
            info.AddValue(control.Name, control.Text);
        }

    }

}

The idea is, enumerate the form, put every value into SerializationInfo stream, and pull it back out when you create a new object. This will allow my original code for Cloning to work.

Community
  • 1
  • 1
James King
  • 6,233
  • 5
  • 42
  • 63
  • 1
    @james thank you but i need to run methods from the base form, how do i do it – Alex Gordon Nov 05 '10 at 22:36
  • 1
    actually, I have to take my answer back and rethink... you can't mark a Form as serializable, so my approach will not work : ( – James King Nov 05 '10 at 22:44
  • 1
    Okay, added info with how to serialize the form. I'm not sure what you mean by 'need to run methods from the base form'? – James King Nov 05 '10 at 23:10
  • 4
    why go through all this trouble? – bevacqua Nov 05 '10 at 23:18
  • 1
    Because if you want a copy of a form, it means you want a copy of all the controls, their values, etc. As well as any member-level variables you've given to the form. The only way to make copies of these is to enumerate them from within the form in a Clone() or Copy() method. Serialization from within the class means you don't have to expose every control as a public property, which you would have to do if you wanted to make a copy from the outside. – James King Nov 05 '10 at 23:26