yonan2236
yonan2236

Reputation: 13659

It is possible to copy all the properties of a certain control? (C# window forms)

For example, I have a DataGridView control with a Blue BackgroundColor property etc.., is there a way which I can transfer or pass programatically these properties to another DataGridView control?

Something like this:

dtGrid2.Property = dtGrid1.Property; // but of course, this code is not working

Thanks...

Upvotes: 8

Views: 22271

Answers (8)

MundoPeter
MundoPeter

Reputation: 734

After having set all the properties in the Designer I then wanted to copy all this configurations to another DataGridView and I faced the same problem. I solved it inspecting the InitializeComponent(); part of the form. There was easy to find all the properies that I had set and to set it again by code to another DataGridView control.

For example, I had set:

DataGridViewCellStyle dgvCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
dgvCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
dgvCellStyle1.BackColor = System.Drawing.SystemColors.Window;
dgvCellStyle1.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
dgvCellStyle1.ForeColor = System.Drawing.SystemColors.ControlText;
dgvCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
dgvCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
dgvCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
dgv.DefaultCellStyle = dgvCellStyle1;
dgv.GridColor = System.Drawing.SystemColors.ControlLight;
dgv.Location = new System.Drawing.Point(258, 315);                    
dgv.ReadOnly = true;
dgv.RowHeadersVisible = false;
dgv.RowTemplate.Height = 18;
dgv.ShowEditingIcon = false;      

Upvotes: 0

Manish Nayak
Manish Nayak

Reputation: 665

I Used below code to copy selected properties.

public static void CloneControl(Control SourceControl, Control DestinationControl)
{
    String[] PropertiesToClone = new String[] { "Size", "Font", "Text", "Tag", "BackColor", "BorderStyle", "TextAlign", "Width", "Margin" };
    PropertyInfo[] controlProperties = SourceControl.GetType().GetProperties();

    foreach (String Property in PropertiesToClone)
    {
        PropertyInfo ObjPropertyInfo = controlProperties.First(a => a.Name == Property);
        ObjPropertyInfo.SetValue(DestinationControl, ObjPropertyInfo.GetValue(SourceControl));
    }
}

Upvotes: 0

elle0087
elle0087

Reputation: 911

i used this:

 Control NewControl=new Control(ControlToClone,ControlToClone.Name);

Upvotes: 0

TaW
TaW

Reputation: 54453

Based on this post here is a version that

  • creates the correct control types and
  • does so recursively

public static class ControlExtensions
{
    public static T Clone<T>(this T controlToClone)  where T : Control
    {
        PropertyInfo[] controlProperties = 
          typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
        //T instance = Activator.CreateInstance<T>();
        Control instance = (Control) Activator.CreateInstance(controlToClone.GetType());

        foreach (PropertyInfo propInfo in controlProperties)
        {
            if (propInfo.CanWrite)
            {
                if (propInfo.Name != "WindowTarget")
                    propInfo.SetValue(instance,
                                      propInfo.GetValue(controlToClone, null), null);
            }
        }

        foreach(Control ctl in controlToClone.Controls)
        {
            instance.Controls.Add( ctl.Clone() );
        }
        return (T) instance;
    }
}

You still may want to test if more than the WindowTarget property should be filtered out..

Funny aside: If the control to clone is (on) an unselected TabPage it will be invisible..

Upvotes: 0

TxCsharper
TxCsharper

Reputation: 656

Here's the code that I came up with. I've only tested it with the Label, TextBox, Panel, and DataGridView controls. For a Panel control you will get all the contained controls (cloned instances). For a DataGridView control you will get the data binding and it will be the exact same data that is bound to the source DataGridView control. Of course, if there is not binding then the cloned instance will have no binding. Whether these behaviors are desirable or not depends on your needs.

private Control CloneControl(Control srcCtl)
{
    var cloned = Activator.CreateInstance(srcCtl.GetType()) as Control;
    var binding = BindingFlags.Public | BindingFlags.Instance;
    foreach(PropertyInfo prop in srcCtl.GetType().GetProperties(binding))
    {
        if (IsClonable(prop))
        {
            object val = prop.GetValue(srcCtl);
            prop.SetValue(cloned, val, null);
        }
    }

    foreach(Control ctl in srcCtl.Controls)
    {
        cloned.Controls.Add(CloneControl(ctl));
    }

    return cloned;
}

private bool IsClonable(PropertyInfo prop)
{
    var browsableAttr = prop.GetCustomAttribute(typeof(BrowsableAttribute), true) as BrowsableAttribute;
    var editorBrowsableAttr = prop.GetCustomAttribute(typeof(EditorBrowsableAttribute), true) as EditorBrowsableAttribute;

    return prop.CanWrite
        && (browsableAttr == null || browsableAttr.Browsable == true)
        && (editorBrowsableAttr == null || editorBrowsableAttr.State != EditorBrowsableState.Advanced);
}

Upvotes: 1

lxwde
lxwde

Reputation: 119

I posted a demo project on codeproject on how to copy&paste or clone a contorl a few years ago, http://www.codeproject.com/Articles/12976/How-to-Clone-Serialize-Copy-Paste-a-Windows-Forms

Upvotes: 2

Kevin Kibler
Kevin Kibler

Reputation: 13605

You could use reflection to get all the public properties of the type and copy the values from one instance to another, but this is dangerous and might not really duplicate the entire state of the object. There might be some properties that you don't want to copy (e.g. Parent, Site), and other important properties that you can't set directly (e.g. Columns, Rows). Also, there could be properties that are reference types; your copied control would end up referencing the same object as your original, which could be undesirable. There could also be state information that can only be set through method calls, which won't be copied this way. In short, reflection probably isn't the solution you're looking for.

You may just have to manually copy the properties you want. Alternatively, you could create a factory method that can create any number of similar grids.

Upvotes: 3

Stuart Helwig
Stuart Helwig

Reputation: 9464

You'll need to use reflection.

You grab a reference to each property in your source control (based on its type), then "get" its value - assigning that value to your target control.

Here's a crude example:

    private void copyControl(Control sourceControl, Control targetControl)
    {
        // make sure these are the same
        if (sourceControl.GetType() != targetControl.GetType())
        {
            throw new Exception("Incorrect control types");
        }

        foreach (PropertyInfo sourceProperty in sourceControl.GetType().GetProperties())
        {
            object newValue = sourceProperty.GetValue(sourceControl, null);

            MethodInfo mi = sourceProperty.GetSetMethod(true);
            if (mi != null)
            {
                sourceProperty.SetValue(targetControl, newValue, null);
            }
        }
    }

Upvotes: 8

Related Questions