探讨.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) ("custom>("err")>
注意,在上面的代码中,我使用一个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("custom>
接下来, EnforceCasing 属性用于指示是否输入的字符应该自动地被转换成大写或小写:
 
 
     
'---用于控制大小写的属性---

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

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

   DescriptionAttribute("实现定制校验的正则表达式。")> _
Public Property RegularExpression() As String
Get
Return _regex
End Get
Set(ByVal value As String)
_regex = value
End Set
End Property("custom>
 
四、事件编程
最后一步是实现与该增强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 ,如需转载请自行联系原作者



相关文章
|
1月前
|
SQL 开发框架 数据可视化
企业应用开发中.NET EF常用哪种模式?
企业应用开发中.NET EF常用哪种模式?
|
2月前
|
开发框架 JavaScript 前端开发
5个.NET开源且强大的快速开发框架(帮助你提高生产效率)
5个.NET开源且强大的快速开发框架(帮助你提高生产效率)
|
4天前
|
开发框架 前端开发 JavaScript
采用C#.Net +JavaScript 开发的云LIS系统源码 二级医院应用案例有演示
技术架构:Asp.NET CORE 3.1 MVC + SQLserver + Redis等 开发语言:C# 6.0、JavaScript 前端框架:JQuery、EasyUI、Bootstrap 后端框架:MVC、SQLSugar等 数 据 库:SQLserver 2012
|
30天前
|
数据安全/隐私保护 Windows
.net三层架构开发步骤
.net三层架构开发步骤
9 0
|
30天前
深入.net平台的分层开发
深入.net平台的分层开发
47 0
|
2月前
|
开发框架 前端开发 .NET
福利来袭,.NET Core开发5大案例,30w字PDF文档大放送!!!
为了便于大家查找,特将之前开发的.Net Core相关的五大案例整理成文,共计440页,32w字,免费提供给大家,文章底部有PDF下载链接。
32 1
福利来袭,.NET Core开发5大案例,30w字PDF文档大放送!!!
|
2月前
|
SQL 开发框架 前端开发
ASP.NET WEB项目中GridView与Repeater数据绑定控件的用法
ASP.NET WEB项目中GridView与Repeater数据绑定控件的用法
32 0
|
3月前
|
C#
.NET开发中合理使用对象映射库,简化和提高工作效率
.NET开发中合理使用对象映射库,简化和提高工作效率
|
3月前
|
开发框架 前端开发 JavaScript
一款基于.NET Core的快速开发框架、支持多种前端UI、内置代码生成器
一款基于.NET Core的快速开发框架、支持多种前端UI、内置代码生成器
|
4月前
|
JavaScript C#
【傻瓜级JS-DLL-WINCC-PLC交互】2.wincc使用C#开发的.net控件
【傻瓜级JS-DLL-WINCC-PLC交互】2.wincc使用C#开发的.net控件
41 0