创建自定义控件 - 提供设计时支持 1






4.49/5 (54投票s)
2005年2月23日
6分钟阅读

202670

4980
本文将介绍如何开发自定义设计时扩展。
引言
在我与 C# 论坛的互动中,我遇到了一些关于为自定义控件提供设计时支持的问题。因此,我想分享一些我在这方面的经验。
设计时支持架构允许我们开发自定义设计时扩展,通过这些扩展,我们可以配置控件/控件的属性。例如:Button 和其他控件的 Dock
、Anchor
属性。在我开发自定义用户控件时,我也遇到了类似的情况,我需要提供用户界面来修改其在设计时期的属性。
让我们简要了解一下 .NET Framework 对此的支持。
.NET 支持
.NET Framework 提供了我们可以用来实现自定义设计时支持的接口。我们可以通过三种方式提供支持。
UITypeEditor
TypeConverter
s- 设计师
UITypeEditors
UITypeEditor
s 允许我们为控件的属性值提供自定义用户界面。它还允许我们在属性窗口中显示当前值的视觉表示。
TypeConverters
TypeConverter
s 允许我们在类型之间转换值。它们还允许我们为属性浏览器中的属性配置提供逻辑。
设计师
Designers 允许我们在设计时自定义控件的行为。
本文将介绍如何使用 UITypeEditor
s 和 TypeConverter
s 来提供设计时支持。Designer 的使用将在下一篇文章中介绍。
使用 UITypeEditor/属性编辑器
.NET 控件的 Dock
、Anchor
属性提供了用于输入/设置其值的用户界面。这些被称为属性编辑器。我们可以使用 .NET Framework 的 UITypeEditor
类为我们的自定义属性创建此类界面。属性编辑器通常显示在属性窗口本身的下拉区域中。但我们也可以让它们显示为模态窗口。
让我们看看如何为我们的自定义属性创建属性编辑器。我们将使用一个自定义控件(Rectangle
控件)来解释这一点。Rectangle 控件绘制一个填充的矩形。该控件公开了两个自定义属性 RectWidth
和 RectHeight
。用户可以使用这些属性来设置矩形的宽度和高度。
如果我们能提供一个用户界面(TrackBar
)来输入这些值,而不是让用户输入值,那会更有用。
图 1:用于设置 RectHeight
和 RectWidth
的属性编辑器
创建属性编辑器的第一步是在属性过程关联的 Editor
属性中指定编辑器(WidthEditor
)。
[Description("Width of the rectangle"),Editor(typeof(WidthEditor),
typeof(UITypeEditor))]
public int RectWidth
{
get{
return this.width;
}
set{
if( value > 0){
this.width = value;
this.Invalidate();
}
}
}
Editor
属性接受两个 System.Type
参数。第一个参数是编辑器的类型。(WidthEditor
- 我们将在第二步中创建它)。第二个参数始终是 typeof(UITypeEditor)
。
第二步,我们需要创建 WidthEditor
类。此类应继承自 System.Drawing.Design.UITypeEditor
类,并且必须重写两个方法。它们是 GetEditStyle()
和 EditValue()
方法。
窗体设计器在填充控件所有属性值的属性窗口时调用 GetEditStyle()
方法。此方法返回一个枚举值,该值告诉设计器属性编辑器将显示在下拉区域还是模态窗体中。在我们的示例中,属性编辑器显示在下拉区域。
public override UITypeEditorEditStyle
GetEditStyle(System.ComponentModel.ITypeDescriptorContext
context)
{
return
UITypeEditorEditStyle.DropDown;
}
当用户单击属性名称旁边的按钮时,窗体设计器会调用 EditValue()
方法。EditValue()
方法创建 TrackBar
控件并为其设置配置详细信息。(例如:范围、方向)。此方法使用 IWindowsFormEditorService
类对象在下拉区域中显示 TrackBar
控件。
IWindowsFormsEditorService frmsvr =
(IWindowsFormsEditorService)provider.GetService(
typeof(IWindowsFormsEditorService));
frmsvr.DropDownControl(tbr); //tbr = Object of Type track
bar
这就是我们所需要做的。现在我们可以通过将此控件添加到窗体设计器来使用它。(附加的解决方案包含 TestCustomControl
项目,该项目使用了此控件)。当我们选择 RectWidth
或 RectHeight
属性时,将显示一个 TrackBar
控件。可以使用 TrackBar
更改这些属性的值。当我们更改这些值时,新值将出现在属性浏览器中,矩形将以当前尺寸重绘。非常简单。对吧?
如果我们希望显示模态窗体而不是将其显示在下拉区域中,我们需要遵循相同的步骤,只有两个区别。
GetEditStyle()
的返回值应为UITypeEditorEditStyle.Modal
。- 我们需要创建一个
Form
类,并将构成编辑器界面的所有控件添加到该Form
中。在EditValue()
方法中,我们需要创建此窗体的实例。现在,要显示此窗体,我们需要调用IWindowsFormsEditorService
类的ShowModal()
方法。
让我们进入本文的第二个主题。使用 TypeConverter
s。
使用 TypeConverters
我们知道一些属性(Font
、Size
)返回对象而不是标量值,并且这些属性在属性浏览器中显示为带有“+”号。如果我们的自定义控件包含返回 .NET Framework 定义的对象(Font
、Point
、Location
、Size
)的属性,那么它们将继承类似的行为。但是,如果我们的自定义控件包含返回自定义对象的属性,我们该如何实现类似的行为呢?要实现这一点,我们需要创建一个自定义 TypeConverter
类。
图 2:带有“+”号的 PhoneData 属性
当前示例使用 PhoneNumber
自定义控件。该控件允许用户输入 Name
、CountryCode
、AreaCode
、PhoneNumber
详细信息。让我们将这些数据暴露在一个属性中,而不是暴露在五个不同的属性中。
这样做的第一步是创建一个 PhoneNumber
类,该类包装所有属性并在任何属性更改时引发 PropertyChanged
事件。我们需要使用 TypeConverter
属性来修饰此类。
[TypeConverter(typeof(PhoneTypeConverter))]
public class PhoneNumber
{
}
TypeConverter
属性告知窗体设计器 PhoneTypeConverter
与 PhoneNumber
类相关联。
第二步,我们需要创建 PhoneTypeConverter
类,该类继承自 System.ComponentModel.TypeConverter
并重写两个方法。它们是 GetPropertiesSupported()
、GetProperties()
方法。
GetPropertiesSupported()
方法返回对象是否支持属性。窗体设计器使用此值来在 PhoneData
属性处显示“+”符号。由于我们的对象支持属性,因此 GetPropertiesSupported()
方法返回 true 值。
GetProperties()
方法返回 PropertiesDescriptorCollection
对象,该对象将描述单击“+”符号时将出现的项。
public override PropertyDescriptorCollection
GetProperties(ITypeDescriptorContext context,
object value, Attribute[] attributes)
{
return
TypeDescriptor.GetProperties(typeof(PhoneNumber));
}
第三步也是最后一步是设置 PhoneData
的 DesignerSerializationVisibility
属性为 Content。
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
DesignerSerializationVisibility
属性指定在设计时序列化控件上的属性时要使用的持久化类型。将此值设置为 Content 会告诉 VS.NET,它应该序列化此 PhoneData
属性的内容。
现在是时候编译和使用控件了。当我们将此控件添加到窗体设计器时,PhoneNumber
控件的 PhoneData
属性将在属性窗口中显示带有“+”号。单击“+”符号将展开所有项。当我们修改任何值时,它将在 PhoneNumber
控件中显示。
结论
在本文中,我们了解了如何使用 PropertyEditor
和 TypeConverter
s 来增强自定义控件的设计时支持。在下一篇文章中,我们将了解如何使用 Designers。