充分利用 .NET 框架的 PropertyGrid 控件(三)

翻译|其它|编辑:郝浩|2006-03-22 10:09:00.000|阅读 2504 次

概述:

# 界面/图表报表/文档/IDE等千款热门软控件火热销售中 >>


提供可展开对象支持

  1. 创建一个从 ExpandableObjectConverter 继承而来的类。
    ' Visual Basic
    
    Public Class SpellingOptionsConverter
        Inherits ExpandableObjectConverter
    End Class
    
    
    //C#
    
    public class SpellingOptionsConverter:ExpandableObjectConverter 
    {  }
  2. 如果 destinationType 参数与使用此类型转换器的类(示例中的 SpellingOptions 类)的类型相同,则覆盖 CanConvertTo 方法并返回 true;否则返回基类 CanConvertTo 方法的值。
    ' Visual Basic
    
    Public Overloads Overrides Function CanConvertTo( _
                                  ByVal context As ITypeDescriptorContext, _
                                  ByVal destinationType As Type) As Boolean
        If (destinationType Is GetType(SpellingOptions)) Then
            Return True
        End If
        Return MyBase.CanConvertTo(context, destinationType)
    End Function
    //C#
    
    public override bool CanConvertTo(ITypeDescriptorContext context,
                                      System.Type destinationType) 
    {
        if (destinationType == typeof(SpellingOptions))
            return true;
    
        return base.CanConvertTo(context, destinationType);
    }
  3. 覆盖 ConvertTo 方法,并确保 destinationType 参数是一个 String,并且值的类型与使用此类型转换器的类(示例中的 SpellingOptions 类)相同。如果其中任一情况为 false,都将返回基类 ConvertTo 方法的值;否则,返回值对象的字符串表示。字符串表示需要使用唯一分隔符将类的每个属性隔开。由于整个字符串都将显示在 PropertyGrid 中,因此需要选择一个不会影响可读性的分隔符,逗号的效果通常比较好。
    ' Visual Basic
    
    Public Overloads Overrides Function ConvertTo( _
                                  ByVal context As ITypeDescriptorContext, _
                                  ByVal culture As CultureInfo, _
                                  ByVal value As Object, _
                                  ByVal destinationType As System.Type) _
                         As Object
        If (destinationType Is GetType(System.String) _
            AndAlso TypeOf value Is SpellingOptions) Then
    
            Dim so As SpellingOptions = CType(value, SpellingOptions)
    
            Return "在键入时检查: " & so.SpellCheckWhileTyping & _
                   ",检查大小写: " & so.SpellCheckCAPS & _
                   ",建议更正: " & so.SuggestCorrections
        End If
        Return MyBase.ConvertTo(context, culture, value, destinationType)
    End Function
    //C#
    
    public override object ConvertTo(ITypeDescriptorContext context,
                                   CultureInfo culture, 
                                   object value, 
                                   System.Type destinationType) 
    {
        if (destinationType == typeof(System.String) && 
             value is SpellingOptions){
    
            SpellingOptions so = (SpellingOptions)value;
    
            return "在键入时检查:" + so.SpellCheckWhileTyping + 
                   ",检查大小写: " + so.SpellCheckCAPS +
                   ",建议更正: " + so.SuggestCorrections;
        }
        return base.ConvertTo(context, culture, value, destinationType);
    }
  4. (可选)通过指定类型转换器可以从字符串进行转换,您可以启用网格中对象字符串表示的编辑。要执行此操作,首先需要覆盖 CanConvertFrom 方法并返回 true(如果源 Type 参数为 String 类型);否则,返回基类 CanConvertFrom 方法的值。
    ' Visual Basic
    
    Public Overloads Overrides Function CanConvertFrom( _
                               ByVal context As ITypeDescriptorContext, _
                               ByVal sourceType As System.Type) As Boolean
        If (sourceType Is GetType(String)) Then
            Return True
        End If
        Return MyBase.CanConvertFrom(context, sourceType)
    End Function
    //C#
    
    public override bool CanConvertFrom(ITypeDescriptorContext context,
                                  System.Type sourceType) 
    {
        if (sourceType == typeof(string))
            return true;
    
        return base.CanConvertFrom(context, sourceType);
    }
  5. 要启用对象基类的编辑,同样需要覆盖 ConvertFrom 方法并确保值参数是一个 String。如果不是 String,将返回基类 ConvertFrom 方法的值;否则,返回基于值参数的类(示例中的 SpellingOptions 类)的新实例。您需要根据值参数解析类的每个属性的值。了解在 ConvertTo 方法中创建的分隔字符串的格式将有助于您的解析。
    ' Visual Basic
    
    Public Overloads Overrides Function ConvertFrom( _
                                  ByVal context As ITypeDescriptorContext, _
                                  ByVal culture As CultureInfo, _
                                  ByVal value As Object) As Object
    
        If (TypeOf value Is String) Then
            Try
                Dim s As String = CStr(value)
                Dim colon As Integer = s.IndexOf(":")
                Dim comma As Integer = s.IndexOf(",")
    
                If (colon <> -1 AndAlso comma <> -1) Then
                    Dim checkWhileTyping As String = s.Substring(colon + 1, _
                                                    (comma - colon - 1))
    
                    colon = s.IndexOf(":", comma + 1)
                    comma = s.IndexOf(",", comma + 1)
    
                    Dim checkCaps As String = s.Substring(colon + 1, _
                                                    (comma - colon - 1))
    
                    colon = s.IndexOf(":", comma + 1)
    
                    Dim suggCorr As String = s.Substring(colon + 1)
    
                    Dim so As SpellingOptions = New SpellingOptions()
    
                    so.SpellCheckWhileTyping = Boolean.Parse(checkWhileTyping)
                    so.SpellCheckCAPS = Boolean.Parse(checkCaps)
                    so.SuggestCorrections = Boolean.Parse(suggCorr)
    
                    Return so
                End If
            Catch
                Throw New ArgumentException( _
                    "无法将“" & CStr(value) & _ 
                                      "”转换为 SpellingOptions 类型")
    
            End Try
        End If
        Return MyBase.ConvertFrom(context, culture, value)
    End Function
    //C#
    
    public override object ConvertFrom(ITypeDescriptorContext context,
                                  CultureInfo culture, object value) 
    {
        if (value is string) {
            try {
                string s = (string) value;
                int colon = s.IndexOf(':');
                int comma = s.IndexOf(',');
    
                if (colon != -1 && comma != -1) {
                    string checkWhileTyping = s.Substring(colon + 1 ,
                                                    (comma - colon - 1));
    
                    colon = s.IndexOf(':', comma + 1);
                    comma = s.IndexOf(',', comma + 1);
    
                    string checkCaps = s.Substring(colon + 1 , 
                                                    (comma - colon -1));
    
                    colon = s.IndexOf(':', comma + 1);
    
                    string suggCorr = s.Substring(colon + 1);
    
                    SpellingOptions so = new SpellingOptions();
    
                    so.SpellCheckWhileTyping =Boolean.Parse(checkWhileTyping);
                    so.SpellCheckCAPS = Boolean.Parse(checkCaps);
                    so.SuggestCorrections = Boolean.Parse(suggCorr);
                        
                    return so;
                }
            }
            catch {
                throw new ArgumentException(
                    "无法将“" + (string)value + 
                                       "”转换为 SpellingOptions 类型");
            }
        }  
        return base.ConvertFrom(context, culture, value);
    }
  6. 现在已经有了一个类型转换器类,下面您需要确定使用该类的目标类。您可以通过将 TypeConverterAttribute 应用到目标类(示例中的 SpellingOptions 类)来执行此操作。
    ' Visual Basic
    
    ' 应用于 SpellingOptions 类的 TypeConverter 特性。
    <TypeConverter(GetType(SpellingOptionsConverter)), _
    DescriptionAttribute("展开以查看应用程序的拼写选项。")> _
    Public Class SpellingOptions
       ...
    End Class
    
    
    //C#
    
    // 应用于 SpellingOptions 类的 TypeConverter 特性。
     [TypeConverterAttribute(typeof(SpellingOptionsConverter)),
    DescriptionAttribute("展开以查看应用程序的拼写选项。")]
    public class SpellingOptions{ ... }

再次编译并运行选项窗口应用程序。下面的屏幕快照显示了选项窗口目前的外观。

图 6:在 PropertyGrid 中显示的带有类型转换器的自定义数据类型

注意: 如果只需要可展开对象支持,而不需要自定义字符串表示,则只需将 TypeConverterAttribute 应用到类中。将 ExpandableObjectConverter 指定为类型转换器类型。

添加域列表和简单的下拉列表属性支持

对于基于 Enum 类型返回枚举的属性,PropertyGrid 会自动在下拉列表中显示枚举值。EnumConverter 也提供了这一功能。对于自己的属性,您可能希望为用户提供一个有效值列表(有时也称为选取列表或域列表),而其类型并不是基于 Enum。如果域值在运行时之前未知,或者值可以更改,则属于这种情况。

修改选项窗口,提供一个用户可从中选择的默认文件名的域列表。您已经将 DefaultFileName 属性添加到 AppSettings 类。下一步是在 PropertyGrid 中显示属性的下拉列表,以提供域列表。

提供简单的下拉列表属性支持

  1. 创建一个从类型转换器类继承而来的类。由于 DefaultFileName 属性属于 String 类型,因此可以从 StringConverter 中继承。如果属性类型的类型转换器不存在,则可以从 TypeConverter 继承;这里并不需要。
    ' Visual Basic
    
    Public Class FileNameConverter
        Inherits StringConverter
    End Class
    
    
    //C#
    
    public class FileNameConverter: StringConverter 
    {  } 
  2. 覆盖 GetStandardValuesSupported 方法并返回 true,表示此对象支持可以从列表中选取的一组标准值。
    ' Visual Basic
    
    Public Overloads Overrides Function GetStandardValuesSupported( _
                        ByVal context As ITypeDescriptorContext) As Boolean
        Return True
    End Function
    
    
    //C#
    
    public override bool GetStandardValuesSupported(
                               ITypeDescriptorContext context) 
    {
        return true;
    }
  3. 覆盖 GetStandardValues 方法并返回填充了标准值的 StandardValuesCollection。创建 StandardValuesCollection 的方法之一是在构造函数中提供一个值数组。对于选项窗口应用程序,您可以使用填充了建议的默认文件名的 String 数组。
    ' Visual Basic
    
    Public Overloads Overrides Function GetStandardValues( _
                         ByVal context As ITypeDescriptorContext) _
                      As StandardValuesCollection
    
        Return New StandardValuesCollection(New String() {"新文件", _
                                                          "文件1", _
                                                          "文档1"})
    End Function 
    
    
    //C#
    
    public override StandardValuesCollection
                         GetStandardValues(ITypeDescriptorContext context) 
    {
        return new StandardValuesCollection(new string[]{"新文件", 
                                                         "文件1", 
                                                         "文档1"});
    } 
  4. (可选)如果希望用户能够键入下拉列表中没有包含的值,请覆盖 GetStandardValuesExclusive 方法并返回 false。这从根本上将下拉列表样式变成了组合框样式。
    ' Visual Basic
    
    Public Overloads Overrides Function GetStandardValuesExclusive( _
                   ByVal context As ITypeDescriptorContext) As Boolean
        Return False
    End Function
    
    
    //C#
    
    public override bool GetStandardValuesExclusive(
                               ITypeDescriptorContext context) 
    {
        return false;
    }
  5. 拥有自己的用于显示下拉列表的类型转换器类后,您需要确定使用该类的目标。在本示例中,目标为 DefaultFileName 属性,因为类型转换器是针对该属性的。将 TypeConverterAttribute 应用到目标属性中。
    ' Visual Basic
    
    ' 应用到 DefaultFileName 属性的 TypeConverter 特性。
    <TypeConverter(GetType(FileNameConverter)), _
     CategoryAttribute("文档设置")> _
    Public Property DefaultFileName() As String
        Get
            Return _defaultFileName
        End Get
        Set(ByVal Value As String)
            _defaultFileName = Value
        End Set
    End Property
    
    
    //C#
    
    // 应用到 DefaultFileName 属性的 TypeConverter 特性。
     [TypeConverter(typeof(FileNameConverter)), 
     CategoryAttribute("文档设置")]
    public string DefaultFileName
    {
        get{ return defaultFileName; }
        set{ defaultFileName = value; }
    }

再次编译并运行选项窗口应用程序。下面的屏幕快照显示了选项窗口目前的外观。请注意 DefaultFileName 属性的外观。

图 7:在 PropertyGrid 中显示下拉域列表

为属性提供自定义 UI

如上所述,.NET 框架类型使用 TypeConverterUITypeEditor 类(以及其他类)来提供 PropertyGrid 编辑支持。有关如何使用 TypeConverter,请参阅对自定义类型的支持一节;您也可以使用 UITypeEditor 类来自定义 PropertyGrid

您可以在 PropertyGrid 中提供小图形表示和属性值,类似于为 ImageColor 类提供的内容。要在自定义中执行此操作,请从 UITypeEditor 继承,覆盖 GetPaintValueSupported 并返回 true。然后,覆盖 UITypeEditor.PaintValue 方法,并在自己的方法中使用 PaintValueEventArgs.Graphics 参数绘制图形。最后,将 Editor 特性应用到使用 UITypeEditor 类的类或属性。

下面的屏幕快照显示了结果外观。

图 8:在 PropertyGrid 中显示属性的自定义图形

您也可以提供自己的下拉列表控件,这与 Control.Dock 属性用来为用户提供靠接选择的控件类似。要执行此操作,请从 UITypeEditor 继承,覆盖 GetEditStyle,然后返回一个 UITypeEditorEditStyle 枚举值,例如 DropDown。您的自定义下拉列表控件必须从 ControlControl 的派生类(例如 UserControl)继承而来。然后,覆盖 UITypeEditor.EditValue 方法。使用 IServiceProvider 参数调用 IServiceProvider.GetService 方法,以获取一个 IWindowsFormsEditorService 实例。最后,调用 IWindowsFormsEditorService.DropDownControl 方法来显示您的自定义下拉列表控件。请记住将 Editor 特性应用到使用 UITypeEditor 类的类或属性中。

下面的屏幕快照显示了结果外观。

图 9:在 PropertyGrid 中显示属性的自定义下拉列表控件

除了使用 TypeEditorUITypeEditor 类外,还可以自定义 PropertyGrid 以显示其他属性选项卡。属性选项卡从 PropertyTab 类继承而来。如果您使用过 Microsoft Visual C#™ .NET 中的属性浏览器,那么就可能看到过自定义的 PropertyTabEvents 选项卡(带有闪电图形的按钮)就是一个自定义的 PropertyTab。下面的屏幕快照显示了自定义 PropertyTab 的另一个示例。可以使用 PropertyTab 编辑按钮的边界点,以创建自定义的按钮形状。

图 10:在 PropertyGrid 中显示自定义选项卡

有关使用 UITypeEditor 类自定义 PropertyGrid 的详细信息,以及上述自定义用户界面代码示例,请参阅 Shawn Burke 的文章 Make Your Components Really RAD with Visual Studio .NET Property Browser(英文)。

小结

.NET 框架提供的 ProperyGrid 控件具有丰富的编辑功能,您可以使用这些编辑功能来改善您的用户界面。PropertyGrid 的自定义非常简单,您可以在任何应用程序中使用这一控件。此外,由于 Visual Studio .NET 属性浏览器是建立在 PropertyGrid 的基础之上的,因此您可以使用这些技术提供更丰富的设计时体验。


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@evget.com


为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP