探讨.NET 2.0定制控件和用户控件开发

简介:
一、引言
伴 随Visual Studio 2005新加入大量的控件(或增强控件),Windows表单应用程序的开发越来越简单。但是,有些情况下,你仍然需要使用更新的功能来进一步增强现有控 件—很典型的一个例子就是TextBox控件。我们知道,TextBox控件允许用户把数据输入到应用程序中,但是自身并没有提供任何类型的校验(例如校 验输入的数据是一个电子邮件地址)和输入过滤(例如限制输入内容仅为数字型)功能。为此,你需要对每一个TextBox控件编写自己的定制校验和过滤逻 辑。显然,当需要在工程中大量地应用这种控件时,需要相当多的重复工作量。
解决这类问题的一种较好的方案就是对内置控件进行扩展—一旦创建这样的增强控件,那么它们的使用思路同原先基本一样,却“悄悄”地加入了我们需要的增强功能。
在本文中,我将使用一个具体的示例—TextBox控件—向你展示如何扩展Windows表单控件。通过扩展TextBox控件,它将实现如下功能:
◆通过过滤限制数据输入—你可以指定用户输入的有效数据类型(例如数字型,字符型或数字字母的组合)。
◆控制大小写—你可以指定输入数据的大小写形式。
◆ 对显示精度进行格式化—你可以指定输入的数字以一位,两位或三位小数形式显示。
◆定制校验—你可以使用正则表达式执行定制校验(例如校验社会安全保险号,邮政编码或电子邮件地址)。
在本文后面部分,我们将讨论如何把多个Windows表单控件结合成单个控件(也即是一个“用户控件”)的问题。
【注】本文源码的调试环境为:Windows XP Professional+Visual Basic.NET 2005。
 
二、扩展Windows表单控件
 
启 动Visual Studio 2005,创建一个新的Windows应用程序并命名为WindowsControls。在本示例中,这个Windows应用程序工程将用作后面我们将扩 展的控件的宿主。现在,在当前方案中添加一个新的类库工程(文件|添加|新建项目…),并命名此工程为EnhancedTextBox。
 
为了在这个工程中扩展一个Windows表单控件,我们需要添加对System.Windows.Forms命名空间的引用(右击“解决方案资源管理器”中的EnhancedTextBox工程名,然后选择“添加引用…”)。随后,导入下列命名空间:
 
Imports System.Windows.Forms
Imports System.ComponentModel
 
接下来,我们定义几个枚举类型,以用于控制大小写,输入内容过滤以及不同的显示精度:
 
Imports System.Windows.Forms
Imports System.ComponentModel
Public Enum Cases
Mixed
UpperOnly
LowerOnly
End Enum
Public Enum FilterTypes
None
IntegerNumeric
DecimalNumeric
AlphabetsOnly
Alphanumeric
End Enum
Public Enum Precisions
None
OneDecimal
TwoDecimal
ThreeDecimal
End Enum
 
因为我们是在扩展 TextBox 控件,所以必须从 System.Windows.Forms.TextBox 下派生 EnhancedTextBox 类:
 

      
      
Public Class EnhancedTextBox
Inherits System.Windows.Forms.TextBox
'---接下来声明成员变量……
 
现在,我们可以声明成员变量以便存储过滤类型,控制大小写,精度,以及用户设置的正则表达式。此外,我们还要定义一个事件,以便当校验失败时,控件用户能够恰当地做出响应:
 
        
        
          _
         
         
Public Class EnhancedTextBox
Inherits System.Windows.Forms.TextBox
'---实现过滤的成员变量---
Private _filterType As FilterTypes = FilterTypes.None
Private _casing As Cases = Cases.Mixed
Private _precision As Precisions = Precisions.None
'---用于实现正则表达式校验的成员变量---
Private _regex As StringPrivate _regexErrMsg As String
'---处理错误的事件处理器---

DescriptionAttribute("错误事件处理器。")> _
Public Event Err(ByVal str As String)
注意,在上面的代码中,我使用一个DefaultEvent属性把Err标识为缺省的出错事件处理器。而且,我还使用Category属性来标识 Err事件,从而把它与属性窗口中的定制属性加以关联(后面,我们将详细讨论之)。另外,DescriptionAttribute指出针对这个事件的描 述信息。
三、声明属性
接下来,我们需要声明各种属性以允许用户控制过滤、精度的类型,并能控制输入内容的大小以及用于定制校验的正则表达式输入。
首先,Precision属性用于指定十进制小数位数—用于控制输入文本的格式:

     
     
'---用于设置精度的属性---

    DescriptionAttribute("十进制小数位数。")> _
Public Property Precision() As Precisions
Get
Return _precision
End Get
Set(ByVal value As Precisions)
_precision = value
End Set
End Property
接下来, EnforceCasing 属性用于指示是否输入的字符应该自动地被转换成大写或小写:
 

        
        
'---用于控制大小写的属性---

    DescriptionAttribute("指示是否输入的字符应该 " & _
"自动地被转换成大写或小写。")> _
Public Property EnforceCasing() As Cases
Get
Return _casing
End Get
Set(ByVal value As Cases)
_casing = value
End Set
End Property
 
接下来, FilterType 属性用于指定允许输入的数据类型:
 

        
        
'---设置过滤类型的属性---

    DescriptionAttribute("指定要应用的过滤器的类型。")> _
Public Property FilterType() As FilterTypes
Get
Return _filterType
End Get
Set(ByVal value As FilterTypes)
_filterType = value
End Set
End Property
 
RegularExpression 属性则允许用户设置要使用的正则表达式,以便用于定制校验:
 

        
        
'---用于设置正则表达式的属性---

   DescriptionAttribute("实现定制校验的正则表达式。")> _
Public Property RegularExpression() As String
Get
Return _regex
End Get
Set(ByVal value As String)
_regex = value
End Set
End Property
 
四、事件编程
最后一步是实现与该增强TextBox控件相关联的各种事件。为了确保用户仅仅可以输入通过我们的过滤器指定的字 符,你可以为该TextBox控件提供相应的KeyPress事件。当输入焦点停在TextBox控件时,无论用户何时按下某个键,都会激活 KeyPress事件。在这个事件中,我们需要实现相应的编程,以便仅允许指定类型的字符显示在本TextBox控件中。该KeyPress事件相应的代 码展示于列表1。
列表1:定制TextBox控件的KeyPress事件编程

     
     
Thread.start { .... }
Private Sub EnhancedTextBox_KeyPress( _
ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyPressEventArgs) _
Handles Me.KeyPress
'---如果没有应用过滤器,则不必作任何进一步处理---
If _filterType = FilterTypes.None Then
Return
End If
'---把字符转换成大/小写---
If _casing = Cases.UpperOnly Then
e.KeyChar = Char.ToUpper(e.KeyChar)
ElseIf _casing = Cases.LowerOnly Then
e.KeyChar = Char.ToLower(e.KeyChar)
End If
'---只允许十进制数字---
If _filterType = FilterTypes.DecimalNumeric Then
'---如果textbox为空并且用户按下某个十进制字符---
If CType(sender, TextBox).Text = String.Empty And e.KeyChar = Chr(46) Then
e.Handled = True
Return
End If
'---如果textbox已经有一个十进制位---
If CType(sender, TextBox).Text.Contains(Chr(46)) And e.KeyChar = Chr(46) Then
e.Handled = True
Return
End If
'---如果用户按键不是一个有效的十进制数---
If (Not (Char.IsDigit(e.KeyChar) Or Char.IsControl(e.KeyChar) Or
(e.KeyChar = Chr(46)))) Then
e.Handled = True
End If
Return
End If
'---只允许整数---
If _filterType = FilterTypes.IntegerNumeric Then
If (Not (Char.IsDigit(e.KeyChar) Or Char.IsControl(e.KeyChar))) Then
e.Handled = True
End If
Return
End If
'---只允许字母(和空格)---
If _filterType = FilterTypes.AlphabetsOnly Then
If (Not (Char.IsLetter(e.KeyChar) Or (e.KeyChar = Chr(32)) Or
Char.IsControl(e.KeyChar))) Then
e.Handled = True
End If
Return
End If
'---只允许字母与数字类型---
If _filterType = FilterTypes.Alphanumeric Then
If (Not (Char.IsLetter(e.KeyChar) Or Char.IsDigit(e.KeyChar) Or (e.KeyChar =
Chr(32)) Or Char.IsControl(e.KeyChar))) Then
e.Handled = True
End If
Return
End If
End Sub
在此,你需要对用户可能输入的各种字符类型进行检查。如果检测到一个无效字符,则把e.Handled属性设置为 True;于是,此字符将不会被添加到该TextBox中。IsControl()方法负责确定是否一个输入的字符是一个控制字符(例如Tab键,回车 键,退格删除键—BackSpace,等等)。在此,进行控制字符检查是很重要的,为什么呢?以BackSpace字符为例;如果在KeyPress事件 中忽略检测BackSpace字符,那么,用户以后可能无法再使用BackSpace键来删除一个输入到该TextBox控件中的字符—这显然与我们的意 愿相违背。
在通过KeyPress事件实现禁止用户输入非法字符的同时,我们还需要在另一个事件—LostFocus事件—中进行一些编程。当输入焦点离开该TextBox控件时将激活这个LostFocus事件—例如按下Tab键导航到下一个控件。
在这个事件中,你需要执行的一个很重要的任务是校验TextBox控件的内容。这是因为无效的字符仍然可能会出现 在该控件中—可能通过其它非直接键盘输入的方法输入;用户可以以编程方式给该TextBox控件赋值,或者把无效的字符直接粘贴(Ctrl-V)到这个 TextBox控件中。例如,如果你使用IntegerNumeric过滤来设置一个TextBox控件,那么,你仍然能通过编程给它赋一个十进制数字 值。在本文示例中,KeyPress事件不能用于限制赋值。因此,在LostFocus事件中,你需要执行各种类型的校验以确保TextBox控件中的值 与指定的过滤相一致。篇幅所限,LostFocus事件相应的代码在此省略,有兴趣的读者可参考本文下载源码。
注意,在本示例中,我们还创建了一个ShowErrorBalloon()方法,用于通过一个汽球小窗(使用ToolTip控件)更为友好地显示一条消息:

       
       
Thread.start { .... }
Public Sub ShowErrorBalloon(ByVal str As String)
Dim toolTip1 As New ToolTip
With toolTip1
.IsBalloon = True
.Show(str, Me,10, -40, 2000)
End With
End Sub
五、测试扩展的TextBox控件
现在,增强控件构建完毕,让我们开始测试这个扩展的TextBox控件。为此,右击“解决方案资源管理器”中的EnhancedTextBox工程并选择“生成”把该工程编译成一个DLL文件。
再回到WindowsControls工程,右击工具箱中的“公共控件”选项卡并选择“选择项…”。
在“选择工具箱项”窗口中,点击“浏览…”按钮并导航到工程的bin\Debug文件夹,然后选择EnhancedTextBox.dll(见图1),并点击“打开”按钮。
 
图1.选择EnhancedTextBox.dll
现在,该EnhancedTextBox控件会出现在工具箱中。于是,我们可以把它的一个副本拖动到WindowsControls工程的缺省的Form1表单中(见图2)。
 
图2.把EnhancedTextBox控件拖动到表单Form1
右击新添加的EnhancedTextBox控件并且选择“属性”。现在,我们会看到这个控件的属性窗口。如果你切换到“分类”视图,你会发现它们位于“Custom Properties”分类下(见图3)。现在,你可以使用属性窗口设置各种定制属性了。
 
图3.定制EnhancedTextBox控件的属性和事件
作为选择,你还可以以编程方式设置属性,如下所示:

     
     
'---第一个例子---
With EnhancedTextBox1
.FilterType = EnhancedTextBox.FilterTypes.DecimalNumeric
.Precision = EnhancedTextBox.Precisions.TwoDecimal
End With
'---第二个例子---
With EnhancedTextBox1
.RegularExpression = _
"^[\w-\.]{1,}\@([\da-zA-Z-]{1,}\.){1,}[\da-zA-Z-]{2,3}$"
.RegularExpressionErrorMessage = _
"电子邮件地址不正确"
End With
为了更为方便地测试新的扩展控件,我在表单上添加了一些控件(见图4)。为了更为直观地说明问题,这个表单还展示 各种过滤器之间的逻辑关系。例如,如果你选择DecimalNumeric过滤,那么,仅应用精度格式控制;而如果你选择AlphabetsOnly或 Alphanumeric过滤器,那么,仅应用大小写格式控制。如果输入一个正则表达式,那么,在控制失去焦点后将校验输入的文本。
 
图4.用于测试EnhancedTextBox控件的屏幕
 
图5.使用汽球窗口显示用户校验失败
如果输入的文本没有通过校验,将显示一个汽球窗口(见图5)。
六、开发用户控件
前面,你学习了如何使用各种过滤器和格式化来扩展VS2005内置的TextBox控件。如今,你可以很容易地使用新的增强的TextBox控件来执行各种类型的输入过滤,而不必再担心其它细节问题了。
除了能够扩展单个的Windows表单控件之外,我们还可以把它们组合成一个单一的控件—这可以通过使用 Windows控件库的工程类型来实现。借助于前面创建的EnhancedTextBox控件,我们可能想把许多这样的控件组合到一起而形成一个新的控件 (称为“用户控件”),例如,一个包含两个TextBox控件的控件,从而允许用户成组地输入自己的名字和电子邮件地址。现在,让我们进行这样的试验。
还是使用前面的方案,但是,要把一个新的“Windows控件库”工程添加到当前方案中(文件|添加|新建项 目…,在随后弹出的“添加新项目”对话框中选择“Windows控件库”模板),然后把这个新工程命名为WindowsControlLibrary1。 通过图6你可以看到该控件的缺省设计布局。
 
图6.用户控件设计视图
 
图7.使用一个标签和增强的TextBox控件填充用户控件
然后,按图7所示,在屏幕上添加两对Label和EnhancedTextBox,并按表格1所示设置各个控件的属性。
表格1. 组成用户控件的各种子控件的属性值。
控件
属性
UserControl1
BorderStyle
FixedSingle.
txtE_Name
FilterType
AlphabetsOnly
txtE_Email
RegularExpression
"^[\w-\.]{1,}\@([\da-zA-Z-]{1,}\.){1,}[\da-zA-Z-]{2,3}$"
txtE_Email
RegularExpressionErrorMessage
“电子邮件格式不正确。”

双击该用户控件,切换到其code-behind代码部分。在此,你将添加两个成员变量和两个属性以允许用户设置用户名和电子邮件地址:

      
      
Public Class UserControl1
Private _Name As String
Private _Email As String
Public Property UserName() As String
Get
Return txtE_Name.Text
End Get
Set(ByVal value As String)
txtE_Name.Text = value
End Set
End Property
Public Property Email() As String
Get
Return txtE_Email.Text
End Get
Set(ByVal value As String)
txtE_Email.Text = value
End Set
End Property
 
然后,在该用户控件的设计视图中,双击txtE_Email控件,系统将为我们自动创建Err事件处理器:
 

      
      
Private Sub txtE_Email_Err(ByVal str As System.String) _
Handles txtE_Email.Err
With txtE_Email
.BackColor = Color.LightYellow
End With
End Sub
 
无论何时存在一个校验错误,这个事件都会激活。在本例中,在校验失败时,该控件的背景色将被设置为浅黄色。
 
七、测试用户控件
 
现在,我们开始测试这个新的用户控件。右击“解决方案资源管理器”中的UserControl工程并选择“生成”从而把该工程编译成一个DLL。
 
返回到WindowsControls工程,右击工具箱中的“公共控件”选项卡并选择“选择项…”。在“选择工具箱 项”窗口,点击“浏览…”按钮,导航到工程的bin\Debug文件夹,并选择WindowsControlLibrary1.dll;最后点击“打 开”。现在,用户控件应该出现在工具箱中。最后,把它拖动到表单Form1的底部(见图8)。
 
 
 
图8.应用中的新用户控件
 
 
 
图9.通过一个黄色小气球中显示错误消息来通知用户输入校验失败
 
试着在第一个控件中输入你的名字,再按Tab键转到下一个控件。如果你输入一个无效电子邮件地址,然后按Tab键使其失去焦点,这时将出现一个汽球,并且其背景色改变为浅黄色(见图9)。
 
八、小结
 
在本文中,我们通过一个简单但较全面的例子探讨了如何扩展Windows表单控件并且把它们打包为新的用户控件的过程。在实际开发中,特别是在工程中反复应用到某些相同功能的控件时进行这样的扩展显然能极大地提高生产效率。

















本文转自朱先忠老师51CTO博客,原文链接: http://blog.51cto.com/zhuxianzhong/59826 ,如需转载请自行联系原作者



相关文章
|
27天前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
86 3
|
21天前
|
JSON C# 开发者
C#语言新特性深度剖析:提升你的.NET开发效率
【10月更文挑战第15天】C#语言凭借其强大的功能和易用性深受开发者喜爱。随着.NET平台的演进,C#不断引入新特性,如C# 7.0的模式匹配和C# 8.0的异步流,显著提升了开发效率和代码可维护性。本文将深入探讨这些新特性,助力开发者在.NET开发中更高效地利用它们。
30 1
|
27天前
|
开发框架 NoSQL MongoDB
C#/.NET/.NET Core开发实战教程集合
C#/.NET/.NET Core开发实战教程集合
|
21天前
|
开发者 Windows
.NET 开源扁平化、美观的 C/S 控件库
【10月更文挑战第23天】介绍了三款适用于 .NET 平台的开源扁平化、美观的 C/S 控件库:MaterialSkin 采用 Google Material Design 风格,适合现代感界面;Krypton Toolkit 提供丰富控件,界面易于定制;Fluent Ribbon Control Suite 模仿 Office 界面,适合复杂功能应用。每款控件库均附有示例代码及 GitHub 链接。
|
27天前
|
C# Windows
一款基于.NET开发的简易高效的文件转换器
一款基于.NET开发的简易高效的文件转换器
|
27天前
|
开发框架 缓存 前端开发
WaterCloud:一套基于.NET 8.0 + LayUI的快速开发框架,完全开源免费!
WaterCloud:一套基于.NET 8.0 + LayUI的快速开发框架,完全开源免费!
|
27天前
|
前端开发 JavaScript C#
CodeMaid:一款基于.NET开发的Visual Studio代码简化和整理实用插件
CodeMaid:一款基于.NET开发的Visual Studio代码简化和整理实用插件
|
27天前
|
C# Android开发 iOS开发
一组.NET MAUI绘制的开源控件 - AlohaKit
一组.NET MAUI绘制的开源控件 - AlohaKit
|
前端开发 JavaScript .NET
NET中验证控件表达式汇总
ASP.NET为开发人员提供了一整套完整的服务器控件来验证用户输入的信息是否有效。这些控件如下:     1、RequiredFieldValidator:验证一个必填字段,如果这个字段没填,那么,将不能提交信息。
988 0
|
2月前
|
开发框架 前端开发 JavaScript
ASP.NET MVC 教程
ASP.NET 是一个使用 HTML、CSS、JavaScript 和服务器脚本创建网页和网站的开发框架。
38 7
下一篇
无影云桌面