2010-08-13 22 views

Respuesta

4

Tendrá que usar la reflexión.

Hace referencia a cada propiedad en su control de origen (según su tipo), luego "obtiene" su valor, asignando ese valor a su control objetivo.

Aquí está un ejemplo crudo:

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

Observe el comentario bajo la respuesta de CodeSawyGeek: este código copia ciegamente todas las propiedades. Podría ser peligroso. –

+1

Hm, busca un método establecido pero no un método get (aunque admito que las propiedades de solo escritura son raras). Pero tenga en cuenta que su código podría copiar propiedades como 'Parent',' Name' y 'Location' que pueden no ser deseadas. – Timwi

+0

Usar la reflexión de esta manera probablemente no le dará los resultados que desea. Un DataGridView es un objeto muy complejo, y es posible que no pueda copiarlo por completo (o correctamente) copiando ciegamente los valores de sus propiedades. –

2

Se podría utilizar la reflexión para obtener todas las propiedades públicas del tipo y copiar los valores de un caso a otro, pero esto es peligroso y podría no duplicar realmente todo el estado del objeto. Es posible que haya algunas propiedades que no desee copiar (por ejemplo, Principal, Sitio) y otras propiedades importantes que no puede configurar directamente (por ejemplo, Columnas, Filas). Además, podría haber propiedades que son tipos de referencia; su control copiado terminaría haciendo referencia al mismo objeto que su original, lo que podría ser indeseable. También podría haber información de estado que solo se puede establecer a través de llamadas a métodos, que no se copiarán de esta manera. En resumen, la reflexión probablemente no sea la solución que estás buscando.

Puede que tenga que copiar manualmente las propiedades que desee. Alternativamente, podría crear un método de fábrica que pueda crear cualquier cantidad de cuadrículas similares.

+1

... Sin embargo, tiene que ser cuidado porque si lo haces a ciegas, terminarías copiando propiedades como 'Parent',' Name' y 'Location' que no querrías. – Timwi

+0

@Timwi: modifiqué mi respuesta para señalar los peligros de utilizar la reflexión de esta manera. –

+0

+1 Para el método de fábrica, aunque probablemente sea más probable que configure el control ya instanciado, por lo que no es una verdadera fábrica, sino la misma idea y es la forma en que lo haré. – andyhasit

0

He utilizado este código para el clon control, porque quiero copiar solo las propiedades seleccionadas.

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

Aquí está el código que se me ocurrió. Solo lo he probado con los controles Label, TextBox, Panel y DataGridView. Para un control de panel obtendrá todos los controles contenidos (instancias clonadas). Para un control DataGridView obtendrá el enlace de datos y serán exactamente los mismos datos que están vinculados al control DataGridView de origen. Por supuesto, si no hay un enlace, entonces la instancia clonada no tendrá ningún enlace. Si estos comportamientos son deseables o no depende de sus necesidades.

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

'System.ComponentModel.DefaultValueAttribute' y' System.ComponentModel.CategoryAttribute' son otros 2 para verificar; si están presentes, la propiedad debe aparecer en el diseñador. Muchas de las propiedades de DGV no tienen navegable o editor navegable, pero tienen una o ambas opciones, p. Ej. las propiedades 'AllowUserTo *'. –

0

Basado en this post aquí es una versión que

  • crea los tipos de control correctas y
  • lo hace de forma recursiva

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

Es posible que aún desee prueba si es más de th e WindowTarget propiedad se debe filtrar ..

divertido a un lado: Si el control de clon es un (a) un no seleccionadaTabPage será invisible ..

0

i utilizado este:

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

Cloud explica su solución un poco. Se ve bien, pero sin más explicaciones, la respuesta puede eliminarse debido a la baja calidad. Ayude a los visitantes a comprender la respuesta y proporcione los motivos para usarla. –

Cuestiones relacionadas