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

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

Mark Rideout
Microsoft Corporation

摘要: 本文旨在帮助您了解 Microsoft .NET 框架中的 PropertyGrid 控件,以及如何针对您的应用程序自定义该控件。

适用于:
Microsoft® .NET® 框架
Microsoft® Visual Studio® .NET

目录

PropertyGrid 控件简介 创建 PropertyGrid 控件 何处使用 PropertyGrid 控件 选择对象 自定义 PropertyGrid 控件 显示复杂属性 为属性提供自定义 UI 小结

PropertyGrid 控件简介

如果您使用过 Microsoft® Visual Basic® 或 Microsoft Visual Studio .NET,那么您一定使用过属性浏览器来浏览、查看和编辑一个或多个对象的属性。.NET 框架 PropertyGrid 控件是 Visual Studio .NET 属性浏览器的核心。 PropertyGrid 控件显示对象或类型的属性,并主要通过使用反射来检索项目的属性。(反射是在运行时提供类型信息的技术。)

下面的屏幕快照显示了 PropertyGrid 在窗体上的外观。

![](http://www.microsoft.com/china/msdn/Archives/library/dndotnet/images/usingpropgrid01.gif)

图 1:窗体上的 PropertyGrid

PropertyGrid 包含以下部分:

  • 属性
  • 可展开属性
  • 属性类别标题
  • 属性说明
  • 属性编辑器
  • 属性选项卡
  • 命令窗格(显示控件设计器提供的设计器操作)

创建 PropertyGrid 控件

要使用 Visual Studio .NET 创建 PropertyGrid 控件,需要将该控件添加到工具箱中,因为默认情况下并不包含该控件。在 Tools (工具)菜单中,选择 Customize Toolbox (自定义工具箱)。在对话框中选择 Framework Components (框架组件)选项卡,然后选择 PropertyGrid

如果您从命令行编译代码,请使用 /reference 选项并指定 System.Windows.Forms.dll。

以下代码显示了如何创建 PropertyGrid 控件并将其添加到窗体中。

**' Visual Basic** Imports System
Imports System.Drawing
Imports System.ComponentModel
Imports System.Windows.Forms
Imports System.Globalization

Public Class OptionsDialog
   Inherits System.Windows.Forms.Form

   Private OptionsPropertyGrid As System.Windows.Forms.PropertyGrid

   Public Sub New()
      MyBase.New()

      OptionsPropertyGrid = New PropertyGrid()
      OptionsPropertyGrid.Size = New Size(300, 250)

      Me.Controls.Add(OptionsPropertyGrid)
      Me.Text = "选项对话框"
   End Sub
End Class


**//C#**

using System;
using System.Drawing;
using System.ComponentModel;
using System.Windows.Forms;
using System.Globalization;

public class OptionsDialog : System.Windows.Forms.Form
{
   private System.Windows.Forms.PropertyGrid OptionsPropertyGrid;
   public OptionsDialog()
   {
      OptionsPropertyGrid = new PropertyGrid();
      OptionsPropertyGrid.Size = new Size(300, 250);

      this.Controls.Add(OptionsPropertyGrid);
      this.Text = "选项对话框";
   }

   [STAThread]
   static void Main() 
   {
      Application.Run(new OptionsDialog());
   }
}

何处使用 PropertyGrid 控件

在应用程序中的很多地方,您都可以使用户与 PropertyGrid 进行交互,从而获得更丰富的编辑体验。例如,某个应用程序包含多个用户可以设置的“设置”或选项,其中一些可能十分复杂。您可以使用单选按钮、组合框或文本框来表示这些选项。但本文将逐步介绍如何使用 PropertyGrid 控件创建选项窗口来设置应用程序选项。上面所创建的 OptionsDialog 窗体即是选项窗口的开始。现在,我们创建一个名为 AppSettings 的类,其中包含映射到应用程序设置的所有属性。如果创建单独的类而不使用多个分散的变量,设置将更便于管理和维护。

**' Visual Basic** Public Class AppSettings
    Private _saveOnClose As Boolean = True
    Private _greetingText As String = "欢迎使用应用程序!"
    Private _maxRepeatRate As Integer = 10
    Private _itemsInMRU As Integer = 4

    Private _settingsChanged As Boolean = False
    Private _appVersion As String = "1.0"

    Public Property SaveOnClose() As Boolean
        Get
            Return _saveOnClose
        End Get
        Set(ByVal Value As Boolean)
            SaveOnClose = Value
        End Set
    End Property

    Public Property GreetingText() As String
        Get
            Return _greetingText
        End Get
        Set(ByVal Value As String)
            _greetingText = Value
        End Set
    End Property

    Public Property ItemsInMRUList() As Integer
        Get
            Return _itemsInMRU
        End Get
        Set(ByVal Value As Integer)
            _itemsInMRU = Value
        End Set
    End Property

    Public Property MaxRepeatRate() As Integer
        Get
            Return _maxRepeatRate
        End Get
        Set(ByVal Value As Integer)
            _maxRepeatRate = Value
        End Set
    End Property

    Public Property SettingsChanged() As Boolean
        Get
            Return _settingsChanged
        End Get
        Set(ByVal Value As Boolean)
            _settingsChanged = Value
        End Set
    End Property

    Public Property AppVersion() As String
        Get
            Return _appVersion
        End Get
        Set(ByVal Value As String)
            _appVersion = Value
        End Set
    End Property
End Class


**//C#**

public class AppSettings{
    private bool saveOnClose = true;
    private string greetingText = "欢迎使用应用程序!";
    private int itemsInMRU = 4;
    private int maxRepeatRate = 10;
    private bool settingsChanged = false;
    private string appVersion = "1.0";
    
    public bool SaveOnClose
    {
        get { return saveOnClose; }
        set { saveOnClose = value;}
    }
    public string GreetingText
    {
        get { return greetingText; }
        set { greetingText = value; }
    }
    public int MaxRepeatRate
    {
        get { return maxRepeatRate; }
        set { maxRepeatRate = value; }
    }
    public int ItemsInMRUList
    {
        get { return itemsInMRU; }
        set { itemsInMRU = value; }
    }
    public bool SettingsChanged
    {
        get { return settingsChanged; }
        set { settingsChanged = value; }
    }
    public string AppVersion
    {
        get { return appVersion; }
        set { appVersion = value; }
    }
}

选项窗口上的 PropertyGrid 将使用此类,因此请将类定义添加到应用程序项目中,在添加时可创建新文件或将其添加到现有窗体源代码的下方。

选择对象

要标识 PropertyGrid 显示的内容,请将 PropertyGrid.SelectedObject 属性设置为一个对象实例。然后, PropertyGrid 将完成其余的工作。每次设置 SelectedObject 时, PropertyGrid 都会刷新显示的属性。这提供了一种简单的方法来强制刷新属性,或在运行时切换对象。您还可以调用 PropertyGrid.Refresh 方法来刷新属性。

接下来,您需要更新 OptionsDialog 构造函数中的代码,以创建一个 AppSettings 对象,并将其设置为 PropertyGrid.SelectedObject 属性的值。

**' Visual Basic**   Public Sub New()
      MyBase.New()

      OptionsPropertyGrid = New PropertyGrid()
      OptionsPropertyGrid.Size = New Size(300, 250)

      Me.Controls.Add(OptionsPropertyGrid)
      Me.Text = "选项对话框"

**' 创建 AppSettings 类并在 PropertyGrid 中显示该类。**
**Dim appset as AppSettings = New AppSettings()**
**OptionsPropertyGrid.SelectedObject = appset**
   End Sub


**//C#**

   public OptionsDialog()
   {
      OptionsPropertyGrid = new PropertyGrid();
      OptionsPropertyGrid.Size = new Size(300, 250);

      this.Controls.Add(OptionsPropertyGrid);
      this.Text = "选项对话框";

**// 创建 AppSettings 类并在 PropertyGrid 中显示该类。**
**AppSettings appset = new AppSettings();**
**OptionsPropertyGrid.SelectedObject = appset;**
   }

编译并运行该应用程序。下面的屏幕快照显示了应用程序的外观。

![](http://www.microsoft.com/china/msdn/Archives/library/dndotnet/images/usingpropgrid02.gif)

图 2:PropertyGrid 中选定的 AppSettings 类

自定义 PropertyGrid 控件

您可以修改 PropertyGrid 的某些外观特征以满足自己的需要。可以更改某些属性的显示方式,甚至选择不显示某些属性。那么,如何对 PropertyGrid 进行自定义呢?

更改 PropertyGrid 的外观特征

PropertyGrid 的许多外观特征都可以自定义。下面列出了其中的一部分:

  • 通过 HelpBackColorHelpForeColorHelpVisible 属性可以更改背景颜色、更改字体颜色或隐藏说明窗格。
  • 通过 ToolbarVisible 属性可以隐藏工具栏,通过 BackColor 属性可以更改工具栏的颜色,通过 LargeButtons 属性可以显示大工具栏按钮。
  • 使用 PropertySort 属性可以按字母顺序对属性进行排序和分类。
  • 通过 BackColor 属性可以更改拆分器的颜色。
  • 通过 LineColor 属性可以更改网格线和边框。

本示例中的选项窗口不需要工具栏,因此可以将 ToolbarVisible 设置为 false 。其余属性均保留默认设置。

更改属性的显示方式

要更改某些属性的显示方式,您可以对这些属性应用不同的特性。特性是用于为类型、字段、方法和属性等编程元素添加批注的声明标记,在运行时可以使用反射对其进行检索。下面列出了其中的一部分:

  • DescriptionAttribute - 设置显示在属性下方说明帮助窗格中的属性文本。这是一种为活动属性(即具有焦点的属性)提供帮助文本的有效方法。可以将此特性应用于 MaxRepeatRate 属性。
  • CategoryAttribute - 设置属性在网格中所属的类别。当您需要将属性按类别名称分组时,此特性非常有用。如果没有为属性指定类别,该属性将被分配给 杂项 类别。可以将此特性应用于所有属性。
  • BrowsableAttribute – 表示是否在网格中显示属性。此特性可用于在网格中隐藏属性。默认情况下,公共属性始终显示在网格中。可以将此特性应用于 SettingsChanged 属性。
  • ReadOnlyAttribute – 表示属性是否为只读。此特性可用于禁止在网格中编辑属性。默认情况下,带有 get 和 set 访问函数的公共属性在网格中是可以编辑的。可以将此特性应用于 AppVersion 属性。
  • DefaultValueAttribute – 表示属性的默认值。如果希望为属性提供默认值,然后确定该属性值是否与默认值相同,则可使用此特性。可以将此特性应用于所有属性。
  • DefaultPropertyAttribute – 表示类的默认属性。在网格中选择某个类时,将首先突出显示该类的默认属性。可以将此特性应用于 AppSettings 类。

现在,我们将其中的一些特性应用于 AppSettings 类,以更改属性在 PropertyGrid 中的显示方式。

**' Visual Basic** **< DefaultPropertyAttribute("SaveOnClose")> _**
Public Class AppSettings
    Private _saveOnClose As Boolean = True
    Private _greetingText As String = "欢迎使用应用程序!"
    Private _maxRepeatRate As Integer = 10
    Private _itemsInMRU As Integer = 4

    Private _settingsChanged As Boolean = False
    Private _appVersion As String = "1.0"

**
  1<categoryattribute("文档设置"), **defaultvalueattribute(true)="" _**=""> _**
  2        Public Property SaveOnClose() As Boolean
  3            Get
  4                Return _saveOnClose
  5            End Get
  6            Set(ByVal Value As Boolean)
  7                SaveOnClose = Value
  8            End Set
  9        End Property
 10    
 11    ** <categoryattribute("全局设置"), **defaultvalueattribute("欢迎使用应用程序!")="" **readonlyattribute(true),="" _**=""> _**
 12        Public Property GreetingText() As String
 13            Get
 14                Return _greetingText
 15            End Get
 16            Set(ByVal Value As String)
 17                _greetingText = Value
 18            End Set
 19        End Property
 20    
 21    ** <categoryattribute("全局设置"), **defaultvalueattribute(4)="" _**=""> _**
 22        Public Property ItemsInMRUList() As Integer
 23            Get
 24                Return _itemsInMRU
 25            End Get
 26            Set(ByVal Value As Integer)
 27                _itemsInMRU = Value
 28            End Set
 29        End Property
 30    
 31    ** <descriptionattribute("以毫秒表示的文本重复率。"), **categoryattribute("全局设置"),="" **defaultvalueattribute(10)="" _**=""> _**
 32        Public Property MaxRepeatRate() As Integer
 33            Get
 34                Return _maxRepeatRate
 35            End Get
 36            Set(ByVal Value As Integer)
 37                _maxRepeatRate = Value
 38            End Set
 39        End Property
 40    
 41    ** <browsableattribute(false),** **defaultvalueattribute(false)=""> _**
 42        Public Property SettingsChanged() As Boolean
 43            Get
 44                Return _settingsChanged
 45            End Get
 46            Set(ByVal Value As Boolean)
 47                _settingsChanged = Value
 48            End Set
 49        End Property
 50    
 51    ** <categoryattribute("版本"), **defaultvalueattribute("1.0"),="" **readonlyattribute(true)="" _**=""> _**
 52        Public Property AppVersion() As String
 53            Get
 54                Return _appVersion
 55            End Get
 56            Set(ByVal Value As String)
 57                _appVersion = Value
 58            End Set
 59        End Property
 60    End Class
 61    
 62    
 63    **//C#**
 64    **[DefaultPropertyAttribute("SaveOnClose")]**
 65    public class AppSettings{
 66        private bool saveOnClose = true;
 67        private string greetingText = "欢迎使用应用程序!";
 68        private int maxRepeatRate = 10;
 69        private int itemsInMRU = 4;
 70    
 71        private bool settingsChanged = false;
 72        private string appVersion = "1.0";
 73    
 74    **[CategoryAttribute("文档设置"),**
 75    **DefaultValueAttribute(true)]**
 76        public bool SaveOnClose
 77        {
 78            get { return saveOnClose; }
 79            set { saveOnClose = value;}
 80        }
 81    
 82    **[CategoryAttribute("全局设置"),**
 83    **ReadOnlyAttribute(true),**
 84    **DefaultValueAttribute("欢迎使用应用程序!")]**
 85        public string GreetingText
 86        {
 87            get { return greetingText; }
 88            set { greetingText = value; }
 89        }
 90    
 91    **[CategoryAttribute("全局设置"),**
 92    **DefaultValueAttribute(4)]**
 93        public int ItemsInMRUList
 94        {
 95            get { return itemsInMRU; }
 96            set { itemsInMRU = value; }
 97        }
 98    
 99    **[DescriptionAttribute("以毫秒表示的文本重复率。"),**
100    **CategoryAttribute("全局设置"),**
101    **DefaultValueAttribute(10)]**
102        public int MaxRepeatRate
103        {
104            get { return maxRepeatRate; }
105            set { maxRepeatRate = value; }
106        }
107    
108    **[BrowsableAttribute(false),**
109    **DefaultValueAttribute(false)]**
110        public bool SettingsChanged
111        {
112            get { return settingsChanged; }
113            set { settingsChanged = value; }
114        }
115    
116    **[CategoryAttribute("版本"),**
117    **DefaultValueAttribute("1.0"),**
118    **ReadOnlyAttribute(true)]**
119        public string AppVersion
120        {
121            get { return appVersion; }
122            set { appVersion = value; }
123        }
124    }
125
126将这些特性应用于 ` AppSettings ` 类后,编译并运行该应用程序。下面的屏幕快照显示了应用程序的外观。 
127
128` ![](http://www.microsoft.com/china/msdn/Archives/library/dndotnet/images/usingpropgrid03.gif) `
129
130**图 3:PropertyGrid 中显示的带有类别和默认值的属性**
131
132使用此版本的选项窗口后,您会注意到以下几点: 
133
134  * 显示窗口时,将首先突出显示 ` SaveOnClose ` 属性。 
135  * 选中 ` MaxRepeatRate ` 属性时,说明帮助窗格中将显示“以毫秒表示的文本重复率”。 
136  * ` SaveOnClose ` 属性显示在“文档设置”类别下。其他属性分别显示在“全局设置”和“版本”类别下。 
137  * ` SettingsChanged ` 属性将不再显示。 
138  * ` AppVersion ` 属性为只读。只读属性以灰显文本显示。 
139  * 如果 ` SaveOnClose ` 属性包含的值不是 **true** ,该值将以粗体显示。 **PropertyGrid** 使用粗体文本表示包含非默认值的属性。 
140
141
142
143##  显示复杂属性 
144
145到现在为止,选项窗口显示的都是简单的类型,如整数、布尔值和字符串。那么,如何显示更复杂的类型呢?如果应用程序需要跟踪窗口大小、文档字体或工具栏颜色等信息,该如何处理呢?.NET 框架提供的某些数据类型具有特殊的显示功能,能使这些类型在 **PropertyGrid** 中更具可用性。 
146
147###  对所提供类型的支持 
148
149首先,请更新 ` AppSettings ` 类,为窗口大小( **Size** 类型)、窗口字体( **Font** 类型)和工具栏颜色( **Color** 类型)添加新属性。 
150    
151    
152    **' Visual Basic** <defaultpropertyattribute("saveonclose")> _
153    Public Class AppSettings
154        Private _saveOnClose As Boolean = True
155        Private _greetingText As String = "欢迎使用应用程序!"
156        Private _maxRepeatRate As Integer = 10
157        Private _itemsInMRU As Integer = 4
158    
159        Private _settingsChanged As Boolean = False
160        Private _appVersion As String = "1.0"
161    
162    **Private _windowSize As Size = New Size(100, 100)**
163    **Private _windowFont As Font = New Font("宋体", 9, FontStyle.Regular)**
164    **Private _toolbarColor As Color = SystemColors.Control**
165    
166        <categoryattribute("文档设置"), _="" defaultvalueattribute(true)=""> _
167        Public Property SaveOnClose() As Boolean
168            Get
169                Return _saveOnClose
170            End Get
171            Set(ByVal Value As Boolean)
172                SaveOnClose = Value
173            End Set
174        End Property
175    
176    ** <categoryattribute("文档设置")> _**
177    **Public Property WindowSize() As Size**
178    **Get**
179    **Return _windowSize**
180    **End Get**
181    **Set(ByVal Value As Size)**
182    **_windowSize = Value**
183    **End Set**
184    **End Property**
185    
186    ** <categoryattribute("文档设置")> _**
187    **Public Property WindowFont() As Font**
188    **Get**
189    **Return _windowFont**
190    **End Get**
191    **Set(ByVal Value As Font)**
192    **_windowFont = Value**
193    **End Set**
194    **End Property**
195    
196    ** <categoryattribute("全局设置")> _**
197    **Public Property ToolbarColor() As Color**
198    **Get**
199    **Return _toolbarColor**
200    **End Get**
201    **Set(ByVal Value As Color)**
202    **_toolbarColor = Value**
203    **End Set**
204    **End Property**
205    
206        <categoryattribute("全局设置"), _="" defaultvalueattribute("欢迎使用应用程序!")="" readonlyattribute(true),=""> _
207        Public Property GreetingText() As String
208            Get
209                Return _greetingText
210            End Get
211            Set(ByVal Value As String)
212                _greetingText = Value
213            End Set
214        End Property
215    
216        <categoryattribute("全局设置"), _="" defaultvalueattribute(4)=""> _
217        Public Property ItemsInMRUList() As Integer
218            Get
219                Return _itemsInMRU
220            End Get
221            Set(ByVal Value As Integer)
222                _itemsInMRU = Value
223            End Set
224        End Property
225    
226        <descriptionattribute("以毫秒表示的文本重复率。"), _="" categoryattribute("全局设置"),="" defaultvalueattribute(10)=""> _
227        Public Property MaxRepeatRate() As Integer
228            Get
229                Return _maxRepeatRate
230            End Get
231            Set(ByVal Value As Integer)
232                _maxRepeatRate = Value
233            End Set
234        End Property
235    
236        <browsableattribute(false), defaultvalueattribute(false)=""> _
237        Public Property SettingsChanged() As Boolean
238            Get
239                Return _settingsChanged
240            End Get
241            Set(ByVal Value As Boolean)
242                _settingsChanged = Value
243            End Set
244        End Property
245    
246        <categoryattribute("版本"), _="" defaultvalueattribute("1.0"),="" readonlyattribute(true)=""> _
247        Public Property AppVersion() As String
248            Get
249                Return _appVersion
250            End Get
251            Set(ByVal Value As String)
252                _appVersion = Value
253            End Set
254        End Property
255    End Class
256    
257    
258    **//C#**
259    
260    [DefaultPropertyAttribute("SaveOnClose")]
261    public class AppSettings{
262        private bool saveOnClose = true;
263        private string greetingText = "欢迎使用应用程序!";
264        private int maxRepeatRate = 10;
265        private int itemsInMRU = 4;
266    
267        private bool settingsChanged = false;
268        private string appVersion = "1.0";
269        
270    **private Size windowSize = new Size(100,100);**
271    **private Font windowFont = new Font("宋体", 9, FontStyle.Regular);**
272    **private Color toolbarColor = SystemColors.Control;**
273    
274        [CategoryAttribute("文档设置"),
275        DefaultValueAttribute(true)]
276        public bool SaveOnClose
277        {
278            get { return saveOnClose; }
279            set { saveOnClose = value;}
280        }
281    
282    **[CategoryAttribute("文档设置")]**
283    **public Size WindowSize**
284    **{**
285    **get { return windowSize; }**
286    **set { windowSize = value;}**
287    **}**
288    
289    **[CategoryAttribute("文档设置")]**
290    **public Font WindowFont**
291    **{**
292    **get {return windowFont; }**
293    **set { windowFont = value;}**
294    **}**
295    
296    **[CategoryAttribute("全局设置")]**
297    **public Color ToolbarColor**
298    **{**
299    **get { return toolbarColor; }**
300    **set { toolbarColor = value; }**
301    **}**
302    
303        [CategoryAttribute("全局设置"),
304        ReadOnlyAttribute(true),
305        DefaultValueAttribute("欢迎使用应用程序!")]
306        public string GreetingText
307        {
308            get { return greetingText; }
309            set { greetingText = value; }
310        }
311    
312        [CategoryAttribute("全局设置"),
313        DefaultValueAttribute(4)]
314        public int ItemsInMRUList
315        {
316            get { return itemsInMRU; }
317            set { itemsInMRU = value; }
318        }
319    
320        [DescriptionAttribute("以毫秒表示的文本重复率。"),
321        CategoryAttribute("全局设置"),
322        DefaultValueAttribute(10)]
323        public int MaxRepeatRate
324        {
325            get { return maxRepeatRate; }
326            set { maxRepeatRate = value; }
327        }
328    
329        [BrowsableAttribute(false),
330        DefaultValueAttribute(false)]
331        public bool SettingsChanged
332        {
333            get { return settingsChanged; }
334            set { settingsChanged = value; }
335        }
336    
337        [CategoryAttribute("版本"),
338        DefaultValueAttribute("1.0"),
339        ReadOnlyAttribute(true)]
340        public string AppVersion
341        {
342            get { return appVersion; }
343            set { appVersion = value; }
344        }
345    }
346
347下面的屏幕快照显示了新属性在 **PropertyGrid** 中的外观。 
348
349` ![](http://www.microsoft.com/china/msdn/Archives/library/dndotnet/images/usingpropgrid04.gif) `
350
351**图 4:显示在 PropertyGrid 中的 .NET 框架数据类型**
352
353请注意, ` WindowFont ` 属性带有一个省略号 (...) 按钮,按下该按钮将显示字体选择对话框。此外,还可以展开该属性以显示更多的 **Font** 属性。某些 **Font** 属性提供有关字体的值和详细信息的下拉列表。您可以展开 ` WindowSize ` 属性以显示 **Size** 类型的更多属性。最后,请注意, ` ToolbarColor ` 属性包含一个选定颜色的样本,以及一个用于选择不同颜色的自定义下拉列表。对于这些以及其他数据类型,.NET 框架提供了其他的类,可以使在 **PropertyGrid** 中的编辑更加容易。 
354
355###  对自定义类型的支持 
356
357现在,您需要在 ` AppSettings ` 类中添加另外两个属性,即 ` DefaultFileName ` 和 ` SpellCheckOptions ` 。 ` DefaultFileName ` 属性用于获取或设置字符串; ` SpellCheckOptions ` 属性用于获取或设置 ` SpellingOptions ` 类的实例。 
358
359` SpellingOptions ` 类是一个新类,用于管理应用程序的拼写检查属性。对于何时创建单独的类以管理对象的属性,并没有严格的规定,而取决于您的整个类设计。将 ` SpellingOptions ` 类定义添加到应用程序项目中 - 可以添加到新文件中,也可以添加到窗体源代码的下方。 
360    
361    
362    **' Visual Basic** <descriptionattribute("展开以查看应用程序的拼写选项。")> _
363    Public Class SpellingOptions
364        Private _spellCheckWhileTyping As Boolean = True
365        Private _spellCheckCAPS As Boolean = False
366        Private _suggestCorrections As Boolean = True
367    
368        <defaultvalueattribute(true)> _
369        Public Property SpellCheckWhileTyping() As Boolean
370            Get
371                Return _spellCheckWhileTyping
372            End Get
373            Set(ByVal Value As Boolean)
374                _spellCheckWhileTyping = Value
375            End Set
376        End Property
377    
378        <defaultvalueattribute(false)> _
379        Public Property SpellCheckCAPS() As Boolean
380            Get
381                Return _spellCheckCAPS
382            End Get
383            Set(ByVal Value As Boolean)
384                _spellCheckCAPS = Value
385            End Set
386        End Property
387    
388        <defaultvalueattribute(true)> _
389        Public Property SuggestCorrections() As Boolean
390            Get
391                Return _suggestCorrections
392            End Get
393            Set(ByVal Value As Boolean)
394                _suggestCorrections = Value
395            End Set
396        End Property
397    End Class
398    
399    
400    **//C#**
401    
402    [DescriptionAttribute("展开以查看应用程序的拼写选项。")]
403    public class SpellingOptions{
404        private bool spellCheckWhileTyping = true;
405        private bool spellCheckCAPS = false;
406        private bool suggestCorrections = true;
407    
408        [DefaultValueAttribute(true)]
409        public bool SpellCheckWhileTyping 
410        {
411            get { return spellCheckWhileTyping; }
412            set { spellCheckWhileTyping = value; }
413        }
414    
415        [DefaultValueAttribute(false)]
416        public bool SpellCheckCAPS 
417        {
418            get { return spellCheckCAPS; }
419            set { spellCheckCAPS = value; }
420        }
421        [DefaultValueAttribute(true)]
422        public bool SuggestCorrections 
423        {
424            get { return suggestCorrections; }
425            set { suggestCorrections = value; }
426        }
427    }
428
429再次编译并运行选项窗口应用程序。下面的屏幕快照显示了应用程序的外观。 
430
431` ![](http://www.microsoft.com/china/msdn/Archives/library/dndotnet/images/usingpropgrid05.gif) `
432
433**图 5:在 PropertyGrid 中显示的不带类型转换器的自定义数据类型**
434
435请注意 ` SpellcheckOptions ` 属性的外观。与 .NET 框架类型不同,它不展开或显示自定义的字符串表示。如果要在自己的复杂类型中提供与 .NET 框架类型相同的编辑体验,该如何处理呢?.NET 框架类型使用 **TypeConverter** 和 **UITypeEditor** 类提供大部分 **PropertyGrid** 编辑支持,您也可以使用这些类。 
436
437####  添加可展开属性支持 
438
439要使 **PropertyGrid** 能够展开 ` SpellingOptions ` 属性,您需要创建 **TypeConverter** 。 **TypeConverter** 提供了从一种类型转换为另一种类型的方法。 **PropertyGrid** 使用 **TypeConverter** 将对象类型转换为 **String** ,并使用该 **String** 在网格中显示对象值。在编辑过程中, **TypeConverter** 会将 **String** 转换回对象类型。.NET 框架提供的 **ExpandableObjectConverter** 类可以简化这一过程。 
440
441####  提供可展开对象支持 
442
443  1. 创建一个从 **ExpandableObjectConverter** 继承而来的类。 
444    
445        **' Visual Basic** Public Class SpellingOptionsConverter
446        Inherits ExpandableObjectConverter
447    End Class
448    
449    
450    **//C#**
451    
452    public class SpellingOptionsConverter:ExpandableObjectConverter 
453    {  }
454
455  2. 如果 ` destinationType ` 参数与使用此类型转换器的类(示例中的 ` SpellingOptions ` 类)的类型相同,则覆盖 **CanConvertTo** 方法并返回 **true** ;否则返回基类 **CanConvertTo** 方法的值。 
456    
457        **' Visual Basic** Public Overloads Overrides Function CanConvertTo( _
458                                  ByVal context As ITypeDescriptorContext, _
459                                  ByVal destinationType As Type) As Boolean
460        If (destinationType Is GetType(SpellingOptions)) Then
461            Return True
462        End If
463        Return MyBase.CanConvertTo(context, destinationType)
464    End Function
465    
466        **//C#** public override bool CanConvertTo(ITypeDescriptorContext context,
467                                      System.Type destinationType) 
468    {
469        if (destinationType == typeof(SpellingOptions))
470            return true;
471    
472        return base.CanConvertTo(context, destinationType);
473    }
474
475  3. 覆盖 **ConvertTo** 方法,并确保 ` destinationType ` 参数是一个 **String** ,并且值的类型与使用此类型转换器的类(示例中的 ` SpellingOptions ` 类)相同。如果其中任一情况为 **false** ,都将返回基类 **ConvertTo** 方法的值;否则,返回值对象的字符串表示。字符串表示需要使用唯一分隔符将类的每个属性隔开。由于整个字符串都将显示在 **PropertyGrid** 中,因此需要选择一个不会影响可读性的分隔符,逗号的效果通常比较好。 
476    
477        **' Visual Basic** Public Overloads Overrides Function ConvertTo( _
478                                  ByVal context As ITypeDescriptorContext, _
479                                  ByVal culture As CultureInfo, _
480                                  ByVal value As Object, _
481                                  ByVal destinationType As System.Type) _
482                         As Object
483        If (destinationType Is GetType(System.String) _
484            AndAlso TypeOf value Is SpellingOptions) Then
485    
486            Dim so As SpellingOptions = CType(value, SpellingOptions)
487    
488            Return "在键入时检查: " &amp; so.SpellCheckWhileTyping &amp; _
489                   ",检查大小写: " &amp; so.SpellCheckCAPS &amp; _
490                   ",建议更正: " &amp; so.SuggestCorrections
491        End If
492        Return MyBase.ConvertTo(context, culture, value, destinationType)
493    End Function
494    
495        **//C#** public override object ConvertTo(ITypeDescriptorContext context,
496                                   CultureInfo culture, 
497                                   object value, 
498                                   System.Type destinationType) 
499    {
500        if (destinationType == typeof(System.String) &amp;&amp; 
501             value is SpellingOptions){
502    
503            SpellingOptions so = (SpellingOptions)value;
504    
505            return "在键入时检查:" + so.SpellCheckWhileTyping + 
506                   ",检查大小写: " + so.SpellCheckCAPS +
507                   ",建议更正: " + so.SuggestCorrections;
508        }
509        return base.ConvertTo(context, culture, value, destinationType);
510    }
511
512  4. (可选)通过指定类型转换器可以从字符串进行转换,您可以启用网格中对象字符串表示的编辑。要执行此操作,首先需要覆盖 **CanConvertFrom** 方法并返回 **true** (如果源 **Type** 参数为 **String** 类型);否则,返回基类 **CanConvertFrom** 方法的值。 
513    
514        **' Visual Basic** Public Overloads Overrides Function CanConvertFrom( _
515                               ByVal context As ITypeDescriptorContext, _
516                               ByVal sourceType As System.Type) As Boolean
517        If (sourceType Is GetType(String)) Then
518            Return True
519        End If
520        Return MyBase.CanConvertFrom(context, sourceType)
521    End Function
522    
523        **//C#** public override bool CanConvertFrom(ITypeDescriptorContext context,
524                                  System.Type sourceType) 
525    {
526        if (sourceType == typeof(string))
527            return true;
528    
529        return base.CanConvertFrom(context, sourceType);
530    }
531
532  5. 要启用对象基类的编辑,同样需要覆盖 **ConvertFrom** 方法并确保值参数是一个 **String** 。如果不是 **String** ,将返回基类 **ConvertFrom** 方法的值;否则,返回基于值参数的类(示例中的 ` SpellingOptions ` 类)的新实例。您需要根据值参数解析类的每个属性的值。了解在 **ConvertTo** 方法中创建的分隔字符串的格式将有助于您的解析。 
533    
534        **' Visual Basic** Public Overloads Overrides Function ConvertFrom( _
535                                  ByVal context As ITypeDescriptorContext, _
536                                  ByVal culture As CultureInfo, _
537                                  ByVal value As Object) As Object
538    
539        If (TypeOf value Is String) Then
540            Try
541                Dim s As String = CStr(value)
542                Dim colon As Integer = s.IndexOf(":")
543                Dim comma As Integer = s.IndexOf(",")
544    
545                If (colon &lt;&gt; -1 AndAlso comma &lt;&gt; -1) Then
546                    Dim checkWhileTyping As String = s.Substring(colon + 1, _
547                                                    (comma - colon - 1))
548    
549                    colon = s.IndexOf(":", comma + 1)
550                    comma = s.IndexOf(",", comma + 1)
551    
552                    Dim checkCaps As String = s.Substring(colon + 1, _
553                                                    (comma - colon - 1))
554    
555                    colon = s.IndexOf(":", comma + 1)
556    
557                    Dim suggCorr As String = s.Substring(colon + 1)
558    
559                    Dim so As SpellingOptions = New SpellingOptions()
560    
561                    so.SpellCheckWhileTyping = Boolean.Parse(checkWhileTyping)
562                    so.SpellCheckCAPS = Boolean.Parse(checkCaps)
563                    so.SuggestCorrections = Boolean.Parse(suggCorr)
564    
565                    Return so
566                End If
567            Catch
568                Throw New ArgumentException( _
569                    "无法将“" &amp; CStr(value) &amp; _ 
570                                      "”转换为 SpellingOptions 类型")
571    
572            End Try
573        End If
574        Return MyBase.ConvertFrom(context, culture, value)
575    End Function
576    
577        **//C#** public override object ConvertFrom(ITypeDescriptorContext context,
578                                  CultureInfo culture, object value) 
579    {
580        if (value is string) {
581            try {
582                string s = (string) value;
583                int colon = s.IndexOf(':');
584                int comma = s.IndexOf(',');
585    
586                if (colon != -1 &amp;&amp; comma != -1) {
587                    string checkWhileTyping = s.Substring(colon + 1 ,
588                                                    (comma - colon - 1));
589    
590                    colon = s.IndexOf(':', comma + 1);
591                    comma = s.IndexOf(',', comma + 1);
592    
593                    string checkCaps = s.Substring(colon + 1 , 
594                                                    (comma - colon -1));
595    
596                    colon = s.IndexOf(':', comma + 1);
597    
598                    string suggCorr = s.Substring(colon + 1);
599    
600                    SpellingOptions so = new SpellingOptions();
601    
602                    so.SpellCheckWhileTyping =Boolean.Parse(checkWhileTyping);
603                    so.SpellCheckCAPS = Boolean.Parse(checkCaps);
604                    so.SuggestCorrections = Boolean.Parse(suggCorr);
605                        
606                    return so;
607                }
608            }
609            catch {
610                throw new ArgumentException(
611                    "无法将“" + (string)value + 
612                                       "”转换为 SpellingOptions 类型");
613            }
614        }  
615        return base.ConvertFrom(context, culture, value);
616    }
617
618  6. 现在已经有了一个类型转换器类,下面您需要确定使用该类的目标类。您可以通过将 **TypeConverterAttribute** 应用到目标类(示例中的 ` SpellingOptions ` 类)来执行此操作。 
619    
620        **' Visual Basic** ' 应用于 SpellingOptions 类的 TypeConverter 特性。
621    &lt; ** **TypeConverter(GetType(SpellingOptionsConverter)),** _**
622    DescriptionAttribute("展开以查看应用程序的拼写选项。")&gt; _
623    Public Class SpellingOptions
624       ...
625    End Class
626    
627    
628    **//C#**
629    
630    // 应用于 SpellingOptions 类的 TypeConverter 特性。
631     [ **TypeConverterAttribute(typeof(SpellingOptionsConverter)),**
632    DescriptionAttribute("展开以查看应用程序的拼写选项。")]
633    public class SpellingOptions{ ... }
634
635
636
637
638再次编译并运行选项窗口应用程序。下面的屏幕快照显示了选项窗口目前的外观。 
639
640` ![](http://www.microsoft.com/china/msdn/Archives/library/dndotnet/images/usingpropgrid06.gif) `
641
642**图 6:在 PropertyGrid 中显示的带有类型转换器的自定义数据类型**
643
644&gt; ****注意:** ` ` ** 如果只需要可展开对象支持,而不需要自定义字符串表示,则只需将 **TypeConverterAttribute** 应用到类中。将 **ExpandableObjectConverter** 指定为类型转换器类型。 
645
646####  添加域列表和简单的下拉列表属性支持 
647
648对于基于 **Enum** 类型返回枚举的属性, **PropertyGrid** 会自动在下拉列表中显示枚举值。 **EnumConverter** 也提供了这一功能。对于自己的属性,您可能希望为用户提供一个有效值列表(有时也称为选取列表或域列表),而其类型并不是基于 **Enum** 。如果域值在运行时之前未知,或者值可以更改,则属于这种情况。 
649
650修改选项窗口,提供一个用户可从中选择的默认文件名的域列表。您已经将 ` DefaultFileName ` 属性添加到 ` AppSettings ` 类。下一步是在 **PropertyGrid** 中显示属性的下拉列表,以提供域列表。 
651
652####  提供简单的下拉列表属性支持 
653
654  1. 创建一个从类型转换器类继承而来的类。由于 ` DefaultFileName ` 属性属于 **String** 类型,因此可以从 **StringConverter** 中继承。如果属性类型的类型转换器不存在,则可以从 **TypeConverter** 继承;这里并不需要。 
655    
656        **' Visual Basic** Public Class FileNameConverter
657        Inherits StringConverter
658    End Class
659    
660    
661    **//C#**
662    
663    public class FileNameConverter: StringConverter 
664    {  } 
665
666  2. 覆盖 **GetStandardValuesSupported** 方法并返回 **true** ,表示此对象支持可以从列表中选取的一组标准值。 
667    
668        **' Visual Basic** Public Overloads Overrides Function GetStandardValuesSupported( _
669                        ByVal context As ITypeDescriptorContext) As Boolean
670        Return True
671    End Function
672    
673    
674    **//C#**
675    
676    public override bool GetStandardValuesSupported(
677                               ITypeDescriptorContext context) 
678    {
679        return true;
680    }
681
682  3. 覆盖 **GetStandardValues** 方法并返回填充了标准值的 **StandardValuesCollection** 。创建 **StandardValuesCollection** 的方法之一是在构造函数中提供一个值数组。对于选项窗口应用程序,您可以使用填充了建议的默认文件名的 **String** 数组。 
683    
684        **' Visual Basic** Public Overloads Overrides Function GetStandardValues( _
685                         ByVal context As ITypeDescriptorContext) _
686                      As StandardValuesCollection
687    
688        Return New StandardValuesCollection(New String() {"新文件", _
689                                                          "文件1", _
690                                                          "文档1"})
691    End Function 
692    
693    
694    **//C#**
695    
696    public override StandardValuesCollection
697                         GetStandardValues(ITypeDescriptorContext context) 
698    {
699        return new StandardValuesCollection(new string[]{"新文件", 
700                                                         "文件1", 
701                                                         "文档1"});
702    } 
703
704  4. (可选)如果希望用户能够键入下拉列表中没有包含的值,请覆盖 **GetStandardValuesExclusive** 方法并返回 **false** 。这从根本上将下拉列表样式变成了组合框样式。 
705    
706        **' Visual Basic** Public Overloads Overrides Function GetStandardValuesExclusive( _
707                   ByVal context As ITypeDescriptorContext) As Boolean
708        Return False
709    End Function
710    
711    
712    **//C#**
713    
714    public override bool GetStandardValuesExclusive(
715                               ITypeDescriptorContext context) 
716    {
717        return false;
718    }
719
720  5. 拥有自己的用于显示下拉列表的类型转换器类后,您需要确定使用该类的目标。在本示例中,目标为 ` DefaultFileName ` 属性,因为类型转换器是针对该属性的。将 **TypeConverterAttribute** 应用到目标属性中。 
721    
722        **' Visual Basic** ' 应用到 DefaultFileName 属性的 TypeConverter 特性。
723    &lt; ** **TypeConverter(GetType(FileNameConverter)),** **_****
724     CategoryAttribute("文档设置")&gt; _
725    Public Property DefaultFileName() As String
726        Get
727            Return _defaultFileName
728        End Get
729        Set(ByVal Value As String)
730            _defaultFileName = Value
731        End Set
732    End Property
733    
734    
735    **//C#**
736    
737    // 应用到 DefaultFileName 属性的 TypeConverter 特性。
738     [ ** **TypeConverter(typeof(FileNameConverter)),** **
739     CategoryAttribute("文档设置")]
740    public string DefaultFileName
741    {
742        get{ return defaultFileName; }
743        set{ defaultFileName = value; }
744    }
745
746
747
748
749再次编译并运行选项窗口应用程序。下面的屏幕快照显示了选项窗口目前的外观。请注意 ` DefaultFileName ` 属性的外观。 
750
751` ![](http://www.microsoft.com/china/msdn/Archives/library/dndotnet/images/usingpropgrid07.gif) `
752
753**图 7:在 PropertyGrid 中显示下拉域列表**
754
755##  为属性提供自定义 UI 
756
757如上所述,.NET 框架类型使用 **TypeConverter** 和 **UITypeEditor** 类(以及其他类)来提供 **PropertyGrid** 编辑支持。有关如何使用 **TypeConverter** ,请参阅 对自定义类型的支持 一节;您也可以使用 **UITypeEditor** 类来自定义 **PropertyGrid** 。 
758
759您可以在 **PropertyGrid** 中提供小图形表示和属性值,类似于为 **Image** 和 **Color** 类提供的内容。要在自定义中执行此操作,请从 **UITypeEditor** 继承,覆盖 **GetPaintValueSupported** 并返回 **true** 。然后,覆盖 **UITypeEditor.PaintValue** 方法,并在自己的方法中使用 **PaintValueEventArgs.Graphics** 参数绘制图形。最后,将 **Editor** 特性应用到使用 **UITypeEditor** 类的类或属性。 
760
761下面的屏幕快照显示了结果外观。 
762
763` ![](http://www.microsoft.com/china/msdn/Archives/library/dndotnet/images/usingpropgrid08.gif) `
764
765**图 8:在 PropertyGrid 中显示属性的自定义图形**
766
767您也可以提供自己的下拉列表控件,这与 **Control.Dock** 属性用来为用户提供靠接选择的控件类似。要执行此操作,请从 **UITypeEditor** 继承,覆盖 **GetEditStyle** ,然后返回一个 **UITypeEditorEditStyle** 枚举值,例如 **DropDown** 。您的自定义下拉列表控件必须从 **Control** 或 **Control** 的派生类(例如 **UserControl** )继承而来。然后,覆盖 **UITypeEditor.EditValue** 方法。使用 **IServiceProvider** 参数调用 **IServiceProvider.GetService** 方法,以获取一个 **IWindowsFormsEditorService** 实例。最后,调用 **IWindowsFormsEditorService.DropDownControl** 方法来显示您的自定义下拉列表控件。请记住将 **Editor** 特性应用到使用 **UITypeEditor** 类的类或属性中。 
768
769下面的屏幕快照显示了结果外观。 
770
771` ![](http://www.microsoft.com/china/msdn/Archives/library/dndotnet/images/usingpropgrid09.gif) `
772
773**图 9:在 PropertyGrid 中显示属性的自定义下拉列表控件**
774
775除了使用 **TypeEditor** 和 **UITypeEditor** 类外,还可以自定义 **PropertyGrid** 以显示其他属性选项卡。属性选项卡从 **PropertyTab** 类继承而来。如果您使用过 Microsoft Visual C#™ .NET 中的属性浏览器,那么就可能看到过自定义的 **PropertyTab** 。 **Events** 选项卡(带有闪电图形的按钮)就是一个自定义的 **PropertyTab** 。下面的屏幕快照显示了自定义 **PropertyTab** 的另一个示例。可以使用 **PropertyTab** 编辑按钮的边界点,以创建自定义的按钮形状。 
776
777` ![](http://www.microsoft.com/china/msdn/Archives/library/dndotnet/images/usingpropgrid10.gif) `
778
779**图 10:在 PropertyGrid 中显示自定义选项卡**
780
781有关使用 **UITypeEditor** 类自定义 **PropertyGrid** 的详细信息,以及上述自定义用户界面代码示例,请参阅 Shawn Burke 的文章 Make Your Components Really RAD with Visual Studio .NET Property Browser (英文)。 
782
783##  小结 
784
785.NET 框架提供的 **ProperyGrid** 控件具有丰富的编辑功能,您可以使用这些编辑功能来改善您的用户界面。 **PropertyGrid** 的自定义非常简单,您可以在任何应用程序中使用这一控件。此外,由于 Visual Studio .NET 属性浏览器是建立在 **PropertyGrid** 的基础之上的,因此您可以使用这些技术提供更丰富的设计时体验。</defaultvalueattribute(true)></defaultvalueattribute(false)></defaultvalueattribute(true)></descriptionattribute("展开以查看应用程序的拼写选项。")></categoryattribute("版本"),></browsableattribute(false),></descriptionattribute("以毫秒表示的文本重复率。"),></categoryattribute("全局设置"),></categoryattribute("全局设置"),></categoryattribute("全局设置")></categoryattribute("文档设置")></categoryattribute("文档设置")></categoryattribute("文档设置"),></defaultpropertyattribute("saveonclose")></categoryattribute("版本"),></browsableattribute(false),**></descriptionattribute("以毫秒表示的文本重复率。"),></categoryattribute("全局设置"),></categoryattribute("全局设置"),></categoryattribute("文档设置"),>
Published At
Categories with Web编程
Tagged with
comments powered by Disqus