高级文本框
继承的文本框,具有扩展属性和验证控件。
- 下载 advancedTextboxDLL.zip - 12.6 KB
- 下载 advancedTextbox-noexe.zip - 331.2 KB
- 下载 advancedTextbox.zip - 517.2 KB
引言
我知道在此期间互联网上将会有几个增强的文本框控件可用。但开发我的应用程序时,我需要一些功能,这些功能只分布在几个自定义控件中,而不是集中在一个控件中。因此,这个控件被开发出来了。也许它也能满足您的需求。
背景
此控件具有以下功能:
- 标记,在控件的某个边缘放置一个小彩色三角形
- 标记位置,设置边缘位置
- 上下文菜单,验证控制的剪贴板操作剪切、复制、粘贴、删除
- 输入类型,无验证,验证输入:整数或小数
如果已验证 - 小数位数,允许的小数位数
- 验证/设置输入值范围最大/最小
- 允许/拒绝负数
- 蜂鸣声,如果验证错误则发出系统蜂鸣声
- 闪烁,如果验证错误则闪烁背景色 3 次
- 菜单项,上下文菜单项的文本字符串
Notice:
- 输入的验证仅针对按键或从剪贴板粘贴的值进行。如果值来自数据源列的绑定,则不会进行验证。
- 如果将输入类型设置为Decimal且小数位数为零,则输入与设置为Integer时相同。
- 如果从剪贴板粘贴值,并且输入类型设置为Integer或Decimal。粘贴的文本将作为正确的数字值填充。对于粘贴的小数,所有小数位数将四舍五入到正确的小数位数。对于粘贴的小数和设置了Integer验证,小数将被四舍五入为整数。
- 源代码项目已通过恶意软件和防病毒软件进行了线程检查。未报告线程。
使用代码
第一个 ZIP 文件包含一个包含两个子项目的项目。控件项目和一个 Windows 窗体测试项目。项目使用 VS2012 .NET 4.5 的 VB.NET 开发。第二个 ZIP 文件仅包含控件 DLL 文件。
使用项目解压缩文件,然后用 Visual Studio (VS) 打开它。
使用控件将控件 DLL 保存到控件项目 bin/Debug 文件夹的所需位置,然后像往常一样将其实现到 VS 工具箱中。在设计模式下将控件从工具箱拖到 Windows 窗体上。
控件项目包含三个类。一个用于控件本身(主类clsAdvTexbox.vb),一个用于使用的上下文菜单(clsContextMenu.vb),第三个是辅助类(clsToolBoxIcon.vb)。
我们需要一个自定义上下文菜单,以便能够验证从剪贴板粘贴的文本是否有效。
为了在属性网格中拥有标准文本框控件的所有属性,该控件不是从 UserControl 构建的。而是通过继承构建的。
Public Class advancedTexbox
Inherits TextBox
所有自定义属性 都经过良好文档记录,如下所示(请记住不要忘记imports System.ComponentModel)
<Browsable(True), DisplayName("Triangle Position"), _
Description("Choose Triangle Position"), _
Category("custom Properties")> _
Public Property TriPosition As _TriPos
....
Browsable,在属性网格中显示/隐藏属性。
DisplayName,在属性网格中显示此文本以标识属性。
Description,在属性网格页脚中显示此文本。
Category,如果启用了属性网格分组,则对该属性进行分组。
Visual Studio 工具箱错误 (clsTexBoxIcon)
从 Visual Studio 的第一个版本开始,开发系统就无法在工具箱中正确显示自定义控件的工具箱图标。如果您查看 VS 帮助,会告诉您按照以下方式增强类语句
<Toolboxitem("name.bmp"> _
class form1
但在大多数情况下,这不会起作用。但是,可以通过将类“clsToolBoxIcon.vb”添加到您的项目中来解决此问题。
<Serializable()> Friend Class TheToolboxItem
Inherits ToolboxItem
' ## change the parameter of the GetType Statement to the name of the usercontrol class
Public Sub New(ByVal oType As Type)
MyBase.New(oType)
End Sub
Public Overrides Sub Initialize(ByVal oType As Type)
If Not oType.Equals(GetType(advancedTexbox)) Then
String.Format(CultureInfo.CurrentCulture, _
"constructor {0} must be {1}.",
Me.GetType().FullName, GetType(advancedTexbox).FullName))
End If
MyBase.Initialize(oType)
End Sub
End Class
按原样使用此类。唯一需要做的是更改对自定义控件类的引用。为此,请在GetType语句中填写类名(参见上面粗体文本)。
接下来,您需要按照以下方式更改自定义控件类语句
<ToolboxItem(True)> <ToolboxBitmap(GetType(TheToolboxItem), _
"numTextbox.bmp")> Public Class advancedTexbox
Inherits TextBox
不要忘记以 bmp 格式创建 16x16 像素的图标,并将文件放在项目中。
clsContextMenu
此类创建一个带有剪切、复制、粘贴和删除菜单项的上下文菜单。没有什么特别的,所以这里不作描述。上下文菜单是主自定义文本框控件的嵌套控件。因此,我们需要一些自定义属性“菜单项剪切”等来布局菜单项的文本属性。
clsAdvTextBox
代码文档编写得很好,大多数情况下对于初学者来说也是直观易读的。源代码的各个部分通过区域进行分隔,以提高可读性。繁重的代码部分将在下面进行描述。
在控件的某个边缘绘制一个标记(三角形)。
有时,标记文本框以向用户显示这是一个特殊文本框可能很有用。例如,文本框输入是受控的,或者其输入是强制性的。要绘制标记(彩色三角形,参见上图),我们必须捕获一个窗口事件(WndProc),因为标准文本框没有绘制事件。
' ## draw colored triangle i a corner
' ## if pen color is transparent don't draw
Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
If m.Msg = &HF And Not Triangle Is Pens.Transparent Then ' WM_PAINT
' ## define triangle position
Dim x2, y2 As Integer
Select Case TriPosition
Case _TriPos.Bottom_Left
x2 = 6 : y2 = Me.Height - 6
Case _TriPos.Bottom_Right
x2 = Me.Width - 6 : y2 = Me.Height - 6
Case _TriPos.Top_Left
x2 = 6 : y2 = 6
Case _TriPos.Top_Right
x2 = Me.Width - 6 : y2 = 6
End Select
' ## define triangle shape
Dim points(3) As Point
points(0) = New Point(x2 - 6, y2)
points(1) = New Point(x2, y2 - 4)
points(2) = New Point(x2, y2)
points(3) = New Point(x2 - 6, y2)
' ## draw shape
Dim g As Graphics = Graphics.FromHwnd(m.HWnd)
g.DrawPolygon(Triangle, points)
g.Dispose()
End If
End Sub
三角形的颜色可以通过自定义属性TriangleColor选择,位置可以通过自定义属性TriPosition选择。如果选择的颜色是transparent,则不绘制三角形。为了保持控件的所有元素(文本和三角形)整洁,我们必须调用me.refresh方法来强制控件在控件文本更改时重绘。我们在控件的Me.TextChanged 事件中这样做。
验证输入
为了控制输入,我们使用控件的Me.KeyPress 事件
' ##### Control the input value
Private Sub numericTexbox_KeyPress(sender As Object, e As KeyPressEventArgs) Handles Me.KeyPress
' ## check if validation is required
If InputType = _IType.NoValidation Then Return
' ## check if key pressed is backspace or delete, avoid group seperator
If e.KeyChar = CChar(ChrW(Keys.Back)) Or e.KeyChar = CChar(ChrW(Keys.Delete)) And e.KeyChar <> GroupeSeparator Then
Return
End If
' ## check Range
If Range Then
If Char.IsDigit(e.KeyChar) Then
Dim strTemp As String = Me.Text + e.KeyChar
If Val(strTemp) >= RangeMin And Val(strTemp) <= RangeMax Then Return
End If
Else
' ## check for decimal
If _InputType = 2 And _decimals > 0 And Char.IsDigit(e.KeyChar) Then
' ## check decimal places
Dim temp() = Me.Text.Split(DecSeparator)
If temp.Length = 2 Then
If temp(1).Length <= _decimals - 1 Then Return
ElseIf temp.Length = 1 Then
Return
End If
ElseIf _InputType = 2 And e.KeyChar = DecSeparator AndAlso (Not Me.Text.Contains(DecSeparator)) Then
Return
ElseIf _InputType = 2 And _decimals = 0 Then
_InputType = 1
End If
' ## check integer
If _InputType = 1 And Char.IsDigit(e.KeyChar) Then
DecimalPlaces = 0
Return
End If
' ## check if negativ is allowed and negative is pressed as 1st char (leading negativ sign)
If Me.Text.Length = 0 And e.KeyChar = "-" And _negativ And (Not Me.Text.Contains(DecSeparator)) Then Return
End If
' ## all other cases are not valid
e.Handled = True ' abord key press
If Flash Then timerFlash.Enabled = e.Handled
If e.Handled And BP Then Beep()
End Sub
验证剪贴板操作
为了控制剪贴板操作,我们必须剥离标准的文本框上下文菜单。这可以通过将控件属性me.shortcutsEnabled设置为false来完成。我们在控件的New() 事件中这样做。自定义上下文菜单的定义被外包到单独的类clsContextMenu中,以提高透明度。当单击菜单项时,会触发clsContextMenu类的自定义事件CM_MenueItem,将单击的项目信息传输到控件的主类clsAdvTextbox。
class clsContextMenu:
Public Class cMenue
Inherits ContextMenuStrip
Friend WithEvents mnCut As System.Windows.Forms.ToolStripMenuItem
Friend WithEvents mnCopy As System.Windows.Forms.ToolStripMenuItem
Friend WithEvents mnPaste As System.Windows.Forms.ToolStripMenuItem
Friend WithEvents ToolStripSeparator1 As System.Windows.Forms.ToolStripSeparator
Friend WithEvents mnDel As System.Windows.Forms.ToolStripMenuItem
Public Event MenueItemClicked(ByVal sender)
...
Private Sub mnCopy_Click(sender As Object, e As EventArgs) Handles mnCopy.Click
RaiseEvent MenueItemClicked(sender)
End Sub
Private Sub mnCut_Click(sender As Object, e As EventArgs) Handles mnCut.Click
RaiseEvent MenueItemClicked(sender)
End Sub
Private Sub mnDel_Click(sender As Object, e As EventArgs) Handles mnDel.Click
RaiseEvent MenueItemClicked(sender)
End Sub
Private Sub mnPaste_Click(sender As Object, e As EventArgs) Handles mnPaste.Click
RaiseEvent MenueItemClicked(sender)
End Sub
class clsAdvTextBox:
' ##### control clipboard actions"
Private Sub CM_MenueItemClicked(sender As Object) Handles CM.MenueItemClicked
Select Case sender.name
Case "mnCut"
Clipboard.SetText(Me.SelectedText)
Me.SelectedText = ""
Case "mnCopy"
If Me.SelectedText = "" Then
Clipboard.SetText(Me.Text)
Else
Clipboard.SetText(Me.SelectedText)
End If
Case "mnPaste"
If InputType <> _IType.NoValidation Then
If IsNumeric(Clipboard.GetText) Then
If InputType = _IType.Integer Then
Me.Text = CInt(Clipboard.GetText)
ElseIf InputType = _IType.Decimal Then
If DecimalPlaces = 0 Then
Me.Text = CInt(Clipboard.GetText)
Else
Me.Text = Math.Round(CDbl(Clipboard.GetText), DecimalPlaces)
End If
End If
Else
If Flash Then timerFlash.Enabled = True
If BP Then Beep()
End If
Else
If Me.SelectedText = "" Then
Me.SelectedText = Clipboard.GetText()
Else
Me.Text = Clipboard.GetText
End If
End If
Case "mnDel"
Me.SelectedText = ""
End Select
End Sub
顺便说一句,为了避免三角形标记或背景色闪烁,建议将父窗体的属性DoubleBufferd设置为 true!历史
2014 年 5 月 7 日 - 11:15
- 修正了一些丢失的注释和文本错误。
- 重新编译并重建 ZIP 文件。
- 添加了工具箱图标变通方法的描述
- 添加了工具箱图标变通方法类
- 修正了本地化,为上下文菜单项的文本添加了属性。