C#如何编程创建一个窗体的复制?

3

我正在使用Visual Studio 2008中的WinForms。

我想要创建一个完全复制我的窗体,包括所有控件和事件,以及与我现有代码相同的所有代码。

这在运行时是否可能?我该如何做?

难道不应该有某种类的解决方案,例如:

Form form2 = new Form();
form2 = form1 ???
2个回答

6

只需创建同一类的另一个实例。使用类的实际名称代替基类Form

Form form2 = new Form1();
form2.Show();

@guffa 怎么样才能在那个窗体上运行一个方法呢?例如,如果我想触发新的form2上的点击事件,我该怎么做呢? - Alex Gordon
如果你想在form2之外完成这个操作,你可以将TextBox的Modifiers属性更改为public,然后通过调用form2.YourTextBox.Text = "my text"来设置你的TextBox文本。 - Jay Riggs
@jay 我想这就是问题所在,我应该如何通过编程方式修改公共程序的修改内容? - Alex Gordon
修饰符是 TextBox(和其他控件)的一个属性。您可以在 WinForm 设计器中进行此更改。 - Jay Riggs
@我是一个女孩:不,你没有在运行时生成新的类,你只是创建了同一个类的另一个实例。你无法在运行时更改访问修饰符。 - Guffa
显示剩余6条评论

1

直接将表单序列化并反序列化到第二个变量中。:)我会尝试研究一下并提供更详细的答案。

需要注意一些事项...您想要浅拷贝还是深拷贝?例如,如果表单引用对象,您想要复制引用(这样两个表单都指向同一个对象),还是也要复制该对象?您需要小心...包含对其他对象的引用的对象不能保证它们将被反序列化的顺序

您不需要这样做,但从ICloneable继承是一个好习惯,它只有一个方法Clone()。覆盖此方法的代码类似于以下代码:

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);

}

使用方法:

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

* 编辑 *
实际上,这里在SO上有一个非常好的例子,可以创建一个通用的对象复制器。非常棒!
深度克隆对象


* 编辑 *
序列化表单的问题在于,并不是所有的值都能被序列化...它们没有意义,例如各个控件的句柄。

为了使表单可序列化,您需要实现ISerializable接口,并实现适当的构造函数和GetObjectData()方法。在GetObjectData中,您需要枚举您的控件,并存储您想要复制的属性(例如Text或Value)。构造函数将它们读回来。它看起来像这样:

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);
        }

    }

}

思路是枚举表单,将每个值放入SerializationInfo流中,并在创建新对象时将其拉回。这将使我的原始克隆代码起作用。


1
@james 谢谢你,但我需要从基本表单中运行方法,我该怎么做? - Alex Gordon
1
实际上,我必须收回我的答案并重新思考...你不能将一个窗体标记为可序列化,所以我的方法不起作用:( - James King
1
好的,已添加关于如何序列化表单的信息。我不确定你所说的“需要从基本表单运行方法”的意思是什么? - James King
4
为什么要费这么大的力气呢? - bevacqua
1
因为如果你想要一个表单的副本,那就意味着你想要所有控件、它们的值等的副本,以及你给表单的任何成员级变量。唯一的方法是在Clone()或Copy()方法中从表单内部枚举它们来进行复制。从类内部进行序列化意味着你不必将每个控件公开为公共属性,如果你想从外部进行复制,那么你必须这样做。 - James King

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接