It is possible to copy all the properties of a certain control? (C# window forms)
For example, I have a DataGridVi开发者_如何学Goew
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...
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);
}
}
}
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.
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
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);
}
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..
i used this:
Control NewControl=new Control(ControlToClone,ControlToClone.Name);
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));
}
}
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;
精彩评论