在“写Form设计器尝试() 在窗体上添加控件”的评论中,热心关注者Leejee提出了自定义控件的问题。我于是作了一个小测试,来实现设计器中使用自定义控件。

先要准备一个自定义控件。新建一个Windows控件方案,命名为MyControl, 添加一个名为ComboBoxField的用户控件,在该用户控件上放一个Label和一个ComboBox, 生成解决方案。将生成的dll文件复制到测试目录D:\Dotnet

打开设计器方案,在工程中添加对MyControl.Dll的引用,在主窗体的代码中添加Using MyControl; 然后在有形如toolBoxService.ToolBox.Items.Add(.);的最后加上一行代码:

toolBoxService.ToolBox.Items.Add(new ToolboxItem(typeof(MyControl.ComboBoxField)));

运行方案,确实可以象使用其它标准控件一样使用这个自定义控件。嘿嘿,没有一点意外,还是和以前的试验一样简单。
但是仔细想一想,出问题了,我们需要在工程中添加对控件所在文件的引用,需要在代码中写控件的类名。也就是说我们在写设计器时,就要知道我们要使用哪些自定义控件。而我们在VS中添加自定义控件时,VS事先并不知道我们要加的是什么。要实现这个功能怎么办?理所当然地要用“反射”。

在工程中删除我们刚才添加的引用,并在主窗体代码中删除我们刚写的那两条语句。
在前面写第二条语句的地方写上:

Assembly a1=Assembly.LoadFrom(@"D:\Dotnet\MyControl.dll");
toolBoxService.ToolBox.Items.Add(
new ToolboxItem(a1.GetType("MyControl.ComboBoxField")));

运行方案,效果和前面的一样。好像这里也将动态库文件名以及类型名称硬编码到了代码中,但是可以很简单地做到让这两个字符串从配置文件中读出,这样就可以实现在设计器使用时随意使用自定义控件了

相关章节:
Form设计器尝试() Start
Form设计器尝试() PropertyGrid
Form设计器尝试() 在窗体上添加控件
写Form设计器尝试(四) 修改窗体上的控件属性

后记: 这篇是昨晚写的, 我后来在睡觉时觉得还有点不对, 就是我这个方法是在载入工具箱前就要使用反射, 我猜测VS的做法是在需要使用此控件时才使用反射。这个问题的解决方法是修改ToolboxService。我会在以后的一个较为完善的版本中实现这个功能。2005/11/07