65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.49/5 (54投票s)

2005年2月23日

6分钟阅读

viewsIcon

202670

downloadIcon

4980

本文将介绍如何开发自定义设计时扩展。

引言

在我与 C# 论坛的互动中,我遇到了一些关于为自定义控件提供设计时支持的问题。因此,我想分享一些我在这方面的经验。

设计时支持架构允许我们开发自定义设计时扩展,通过这些扩展,我们可以配置控件/控件的属性。例如:Button 和其他控件的 DockAnchor 属性。在我开发自定义用户控件时,我也遇到了类似的情况,我需要提供用户界面来修改其在设计时期的属性。

让我们简要了解一下 .NET Framework 对此的支持。

.NET 支持

.NET Framework 提供了我们可以用来实现自定义设计时支持的接口。我们可以通过三种方式提供支持。

  • UITypeEditor
  • TypeConverters
  • 设计师

UITypeEditors

UITypeEditors 允许我们为控件的属性值提供自定义用户界面。它还允许我们在属性窗口中显示当前值的视觉表示。

TypeConverters

TypeConverters 允许我们在类型之间转换值。它们还允许我们为属性浏览器中的属性配置提供逻辑。

设计师

Designers 允许我们在设计时自定义控件的行为。

本文将介绍如何使用 UITypeEditors 和 TypeConverters 来提供设计时支持。Designer 的使用将在下一篇文章中介绍。

使用 UITypeEditor/属性编辑器

.NET 控件的 DockAnchor 属性提供了用于输入/设置其值的用户界面。这些被称为属性编辑器。我们可以使用 .NET Framework 的 UITypeEditor 类为我们的自定义属性创建此类界面。属性编辑器通常显示在属性窗口本身的下拉区域中。但我们也可以让它们显示为模态窗口。

让我们看看如何为我们的自定义属性创建属性编辑器。我们将使用一个自定义控件(Rectangle 控件)来解释这一点。Rectangle 控件绘制一个填充的矩形。该控件公开了两个自定义属性 RectWidthRectHeight。用户可以使用这些属性来设置矩形的宽度和高度。

如果我们能提供一个用户界面(TrackBar)来输入这些值,而不是让用户输入值,那会更有用。

Sample screenshot

图 1:用于设置 RectHeightRectWidth 的属性编辑器

创建属性编辑器的第一步是在属性过程关联的 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 项目,该项目使用了此控件)。当我们选择 RectWidthRectHeight 属性时,将显示一个 TrackBar 控件。可以使用 TrackBar 更改这些属性的值。当我们更改这些值时,新值将出现在属性浏览器中,矩形将以当前尺寸重绘。非常简单。对吧?

如果我们希望显示模态窗体而不是将其显示在下拉区域中,我们需要遵循相同的步骤,只有两个区别。

  1. GetEditStyle() 的返回值应为 UITypeEditorEditStyle.Modal
  2. 我们需要创建一个 Form 类,并将构成编辑器界面的所有控件添加到该 Form 中。在 EditValue() 方法中,我们需要创建此窗体的实例。现在,要显示此窗体,我们需要调用 IWindowsFormsEditorService 类的 ShowModal() 方法。

让我们进入本文的第二个主题。使用 TypeConverters。

使用 TypeConverters

我们知道一些属性(FontSize)返回对象而不是标量值,并且这些属性在属性浏览器中显示为带有“+”号。如果我们的自定义控件包含返回 .NET Framework 定义的对象(FontPointLocationSize)的属性,那么它们将继承类似的行为。但是,如果我们的自定义控件包含返回自定义对象的属性,我们该如何实现类似的行为呢?要实现这一点,我们需要创建一个自定义 TypeConverter 类。

Fig2: PhoneData property returning a custom object

图 2:带有“+”号的 PhoneData 属性

当前示例使用 PhoneNumber 自定义控件。该控件允许用户输入 NameCountryCodeAreaCodePhoneNumber 详细信息。让我们将这些数据暴露在一个属性中,而不是暴露在五个不同的属性中。

这样做的第一步是创建一个 PhoneNumber 类,该类包装所有属性并在任何属性更改时引发 PropertyChanged 事件。我们需要使用 TypeConverter 属性来修饰此类。

[TypeConverter(typeof(PhoneTypeConverter))]
public class PhoneNumber
{
}

TypeConverter 属性告知窗体设计器 PhoneTypeConverterPhoneNumber 类相关联。

第二步,我们需要创建 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));
}

第三步也是最后一步是设置 PhoneDataDesignerSerializationVisibility 属性为 Content。

[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]

DesignerSerializationVisibility 属性指定在设计时序列化控件上的属性时要使用的持久化类型。将此值设置为 Content 会告诉 VS.NET,它应该序列化此 PhoneData 属性的内容。

现在是时候编译和使用控件了。当我们将此控件添加到窗体设计器时,PhoneNumber 控件的 PhoneData 属性将在属性窗口中显示带有“+”号。单击“+”符号将展开所有项。当我们修改任何值时,它将在 PhoneNumber 控件中显示。

结论

在本文中,我们了解了如何使用 PropertyEditorTypeConverters 来增强自定义控件的设计时支持。在下一篇文章中,我们将了解如何使用 Designers。

© . All rights reserved.