且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何克隆具有不可序列化属性的Windows窗体控件?

更新时间:2023-12-06 08:34:34

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