Introduction
In the .NET environment, the System.Windows.Forms.Control
class and all the concrete controls derived from it don’t have clone methods and they are not serializable. So there is no immediate way to clone, serialize, or copy & paste them.
This article presents an all-purpose approach to let you clone, serialize, or copy & paste a Windows Forms control through serializing its properties.
Background
Recently, I was doing some UI programming with C#. One problem I met is that I can not clone or copy & paste a Windows Forms control directly because the System.Windows.Forms.Control
class is neither serializable nor does it have a Clone
method. After searching the internet and reading James and Nish’s articles, Clipboard Handling with .NET (Part I, Part II), I came up with my own approach to copy & paste a Windows Forms control by serializing its properties.
Using the code
Using the code in the sample application to clone/serialize/copy & paste a Windows Forms control is very simple. The static methods to do serialization and deserialization are wrapped in the ControlFactory
class.
Copy & Paste a control
...
ControlFactory.CopyCtrl2ClipBoard(this.comboBox1);
...
Control ctrl = ControlFactory.GetCtrlFromClipBoard();
this.Controls.Add(ctrl);
ctrl.Text = "created by copy&paste";
ctrl.SetBounds(ctrl.Bounds.X,ctrl.Bounds.Y+100,
ctrl.Bounds.Width,ctrl.Bounds.Height);
ctrl.Show();
Clone a control
...
Control ctrl = ControlFactory.CloneCtrl(this.comboBox1);
this.Controls.Add(ctrl);
ctrl.Text = "created by clone";
ctrl.SetBounds(ctrl.Bounds.X,ctrl.Bounds.Y+350,
ctrl.Bounds.Width,ctrl.Bounds.Height);
ctrl.Show();
Implementation Details
When you clone/paste a control, the ControlFactory
creates a new control through reflection, with the class name and namespace (partialName
) passed to it.
...
Assembly controlAsm = Assembly.LoadWithPartialName(partialName);
Type controlType = controlAsm.GetType(partialName + "." + ctrlName);
ctrl = (Control)Activator.CreateInstance(controlType);
...
return ctrl;
If the new control is successfully created, ControlFactory
then sets the properties of the new control with the property values it had retrieved from the original control.
public static void SetControlProperties(Control ctrl,Hashtable propertyList)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(ctrl);
foreach (PropertyDescriptor myProperty in properties)
{
if(propertyList.Contains(myProperty.Name))
{
Object obj = propertyList[myProperty.Name];
myProperty.SetValue(ctrl,obj);
}
}
}
In .NET clipboard programming, to create a custom format that uses a class, you must make the class serializable, that is it needs to have the Serializable
attribute applied to it. CBFormCtrl
is such a custom data format, it also uses a hash table to store the serializable properties.
[Serializable()]
public class CBFormCtrl
{
private static DataFormats.Format format;
private string ctrlName;
private string partialName;
private Hashtable propertyList = new Hashtable();
...
}
Points of Interest
I’ve tested this approach with almost all the Windows Forms controls, it works fine with most of them. Unfortunately, when I copy & paste a ListView
/ListBox
/CheckedListBox
or a TreeView
, their item data will be lost, that is because the “Items
” property of a ListView
/ListBox
/CheckedListBox
and the “Node
” property of a TreeView
are not serializable.
To completely copy & paste these controls with their item data, you need to do some extra handling of the “Items
” property or the “Node
” property. As a reference, you can look at Tom John’s article to see how to fully serialize a TreeView
control.