如何克隆具有不可序列化属性的Windows窗体控件? [英] How to Clone a Windows Forms Controls even with non-Serializable properties?

查看:82
本文介绍了如何克隆具有不可序列化属性的Windows窗体控件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何克隆或序列化Windows窗体控件?

当我尝试使用此代码 CloneControl(Control ct1)克隆Windows窗体控件时,它允许我复制具有某些Serializable属性的控件。 ,并非具有所有属性。

How to Clone or Serialize a Windows Forms Control?
When I am trying to Clone windows forms controls using this code "CloneControl(Control ct1)", it allows me to duplicate controls with some Serializable properties, not with all properties.

public Form1()
{
    InitializeComponent();
        Columns = new DataGridViewTextBoxColumn[2];
        for (int i = 0; i < 2; i++)
        {
            Columns[i] = new System.Windows.Forms.DataGridViewTextBoxColumn();
            // 
            // Columns[i]
            // 
            Columns[i].HeaderText = "j" + (i + 1);
            Columns[i].Name = "Column" + (i + 1);
            Columns[i].Width = 50;
        }
        dataGridView1 = new System.Windows.Forms.DataGridView();
        dataGridView1.Name = "dataGridView1";
        dataGridView1.Location = new System.Drawing.Point(100, 100);
        dataGridView1.RowHeadersWidth = 50;
        dataGridView1.RowTemplate.Height = 25;
        dataGridView1.Size = new System.Drawing.Size(55 + 50 * 2, 25 + dataGridView1.RowTemplate.Height * 2);
        dataGridView1.Anchor = System.Windows.Forms.AnchorStyles.None;
        dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
        dataGridView1.Columns.AddRange(Columns);
        dataGridView1.TabIndex = 3;
        dataGridView1.AllowUserToAddRows = false;
        dataGridView1.Rows.Add();
        dataGridView1.Rows.Add();
        dataGridView1.Rows[0].HeaderCell.Value = "i" + 1;
        dataGridView1.Rows[1].HeaderCell.Value = "i" + 2;
        dataGridView1.Rows[0].Cells[0].Value = "value1";
        Controls.Add(dataGridView1);

        Control cloned1 = CloneControl(dataGridView1); 
        cloned1.SetBounds(cloned1.Location.X, cloned1.Location.Y + 300, cloned1.Width, ct1.Height);
        Controls.Add(cloned1);
        cloned1.Show();
}    

public Control CloneControl(Control ct1)
{
    Hashtable PropertyList = new Hashtable();
    PropertyDescriptorCollection Properties = TypeDescriptor.GetProperties(ct1);
    Assembly controlAsm = Assembly.LoadWithPartialName(ct1.GetType().Namespace);
    Type controlType = controlAsm.GetType(ct1.GetType().Namespace + "." + ct1.GetType().Name);
    Control cloned1 = (Control)Activator.CreateInstance(controlType);
    foreach (PropertyDescriptor pr1 in Properties)
    {
        if (pr1.PropertyType.IsSerializable)
        {
            PropertyList.Add(pr1.Name, pr1.GetValue(ct1));
        }
        if (PropertyList.Contains(pr1.Name))
        {
            try
            {
                 Object obj = PropertyList[pr1.Name];
                 pr1.SetValue(cloned1, obj);
            }
            catch (Exception ex)
            {

            }
        }
    }
    return ct2;
}

如果运行代码,您将得到

If you run the code... the you will get

正如您在main方法中看到的那样,我创建了一个dataGridView1的克隆,它具有一些属性。

实际上,在克隆的dataGridView中,每个单元格值都为空。
也不会克隆列的大小!

As you can see in the main method I create a clone of dataGridView1, which has a few properties.
And actually each cell value is null in a cloned dataGridView. Also size of a columns are not cloned!

您可能会有一个问题:如果Visual Studio或SharpDeveloper作为C#编写的IDE可以解决此问题? ,那么就有可能编写这种代码!是吗?
在Visual Studio中
在尝试拖放控件或复制和粘贴控件时,它不仅会复制具有所有属性(包括Serializable或non-Serializable)的控件,还会更改名称。从 dataGridView1到 dataGridView2以及在SharpDeveloper中的控制本身!

You may have a question: if Visual Studio or SharpDeveloper as IDE which is written in C# can handle this problem, then it might be possible to write that kind of code! Right?
In Visual Studio When you are trying drag and drop controls, or copy and paste controls, it not only duplicates that controls with all properties (including Serializable or non-Serializable) but also it changes the name of control itself from "dataGridView1" to "dataGridView2" as well as in SharpDeveloper!

我该怎么办?

我应该使用哪种方法?

也许另一个控件具有许多不可序列化的属性!

如何复制所有这些属性?

What should I do?
What kind of method should I create?
Maybe another control has a many non-Serializable properties!
How to duplicate all of them?

请任何人.....

推荐答案

IDE (例如Visual Studio)正在使用 PropertyDescriptors DesignerSeri alizationVisibility ShouldSerializeValue 但是DataGrid Rows很特别,因为您不能在设计时添加它们! IDE不能复制不存在的内容 ,因此,解决方案必须使用不同的(如果您要克隆控件,而IDE / Designer不能提供这些功能,请参见其他答案和注释) 。尝试我的代码(除网格行外的所有内容都被克隆而无需额外检查-得到了克隆

IDE (e.g. Visual Studio) is using PropertyDescriptors, DesignerSerializationVisibility and ShouldSerializeValue, but DataGrid Rows are something special, because you cannot add them at design time! IDE cannot copy something that is not there, so, the solution must be different (if you want to clone controls beyond what IDE/Designer can do - see other answers and comments for this). Try my code (everything except grid rows got cloned without the extra check - the columns got cloned).

foreach(PropertyDescriptor pd in TypeDescriptor.GetProperties(src)) {
    if(!pd.ShouldSerializeValue(src)) {
        if(src is DataGridView && pd.Name == "Rows")
            CopyDataGridRows((DataGridView)src, (DataGridView)dst);
        continue; }

注意:上面的方法可以做得更好(通过

Note: The above can be done better (by check for the class at the end), but is as it is to be obvious.

using System;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
namespace CloneControls {
    public partial class Form1: Form {
        public Form1() { InitializeComponent(); }
        private void Form1_Load(object sender, EventArgs e) {
            dataGridView1.Rows.Add();
            dataGridView1.Rows.Add();
            foreach(Control c in splitContainer1.Panel1.Controls)
                splitContainer1.Panel2.Controls.Add((Control)Clone(c));
        }

        static object Clone(object o) {
            return Copy(o, Activator.CreateInstance(o.GetType()));
        }
        static object Copy(object src, object dst) {
            IList list = src as IList;
            if(list != null) {
                IList to = dst as IList;
                foreach(var x in list)
                    to.Add(Clone(x));
                return dst; }
            foreach(PropertyDescriptor pd in TypeDescriptor.GetProperties(src)) {
                if(!pd.ShouldSerializeValue(src)) {
                    if(src is DataGridView && pd.Name == "Rows")
                        CopyDataGridRows((DataGridView)src, (DataGridView)dst);
                    continue; }
                switch(pd.SerializationVisibility) {
                default: continue;
                case DesignerSerializationVisibility.Visible:
                    if(pd.IsReadOnly) continue;
                    pd.SetValue(dst, pd.GetValue(src));
                    continue;
                case DesignerSerializationVisibility.Content:
                    Copy(pd.GetValue(src), pd.GetValue(dst));
                    continue;
                }
            }
            return dst;
        }
        static void CopyDataGridRows(DataGridView src, DataGridView dst) {
            foreach(DataGridViewRow row in src.Rows)
                if(!row.IsNewRow) dst.Rows.Add((DataGridViewRow)Clone(row));
        }
    }
}

这篇关于如何克隆具有不可序列化属性的Windows窗体控件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆