如何克隆/序列化/复制和粘贴 Windows Forms 控件
通过序列化其属性来克隆/序列化/复制和粘贴 Windows Forms 控件。
引言
在 .NET 环境中,System.Windows.Forms.Control
类及其派生的所有具体控件都没有克隆方法,并且它们不可序列化。因此,没有直接的方法来克隆、序列化或复制和粘贴它们。
本文介绍了一种通用方法,让您可以通过序列化其属性来克隆、序列化或复制和粘贴 Windows Forms 控件。
背景
最近,我用 C# 做了一些 UI 编程。我遇到的一个问题是我无法直接克隆或复制和粘贴 Windows Forms 控件,因为 System.Windows.Forms.Control
类既不可序列化,也没有 Clone
方法。在搜索互联网并阅读 James 和 Nish 的文章《使用 .NET 处理剪贴板》(第一部分,第二部分)后,我提出了我自己的方法,通过序列化其属性来复制和粘贴 Windows Forms 控件。
使用代码
使用示例应用程序中的代码来克隆/序列化/复制和粘贴 Windows Forms 控件非常简单。用于进行序列化和反序列化的静态方法被封装在 ControlFactory
类中。
复制并粘贴控件
...
//copy a control to clipboard
ControlFactory.CopyCtrl2ClipBoard(this.comboBox1);
...
//then get it from clipboard and add it to its parent form
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 directly and then add it to its parent form
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();
实现细节
当您克隆/粘贴控件时,ControlFactory
通过反射创建一个新控件,并传入它的类名和命名空间 (partialName
)。
//
...
Assembly controlAsm = Assembly.LoadWithPartialName(partialName);
Type controlType = controlAsm.GetType(partialName + "." + ctrlName);
ctrl = (Control)Activator.CreateInstance(controlType);
...
return ctrl;
如果新控件创建成功,ControlFactory
然后使用它从原始控件中检索到的属性值设置新控件的属性。
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);
}
//...
}
}
在 .NET 剪贴板编程中,要创建一个使用类的自定义格式,您必须使该类可序列化,也就是说,它需要应用 Serializable
属性。CBFormCtrl
是这样一个自定义数据格式,它还使用哈希表来存储可序列化的属性。
//
[Serializable()]
public class CBFormCtrl//clipboard form control
{
private static DataFormats.Format format;
private string ctrlName;
private string partialName;
private Hashtable propertyList = new Hashtable();
//
...
}
关注点
我用几乎所有 Windows Forms 控件测试了这种方法,它对它们中的大多数都有效。不幸的是,当我复制和粘贴 ListView
/ListBox
/CheckedListBox
或 TreeView
时,它们的项目数据将会丢失,这是因为 ListView
/ListBox
/CheckedListBox
的 “Items
” 属性和 TreeView
的 “Node
” 属性不可序列化。
要完全复制和粘贴这些控件及其项目数据,您需要对“Items
”属性或“Node
”属性进行一些额外的处理。作为参考,您可以查看 Tom John 的文章,了解如何完全序列化 TreeView
控件。