See Tutorial: Introduction to ExtenderProviders in VB .NET for an overview of creating ExtenderProviders.
This provider stores MinValue, MaxValue, and RangeFieldName values for each of its clients in its private RangeInfo class. It stores RangeInfo objects in its m_RangeInfo hashtable. It also adds an event handler to catch each client control's Validating event.
When that event fires, the provider's ValidateTextBox subroutine determines whether the client TextBox contains a value that is an integer within the desired range. If the TextBox doesn't contain the right value, it assigns an error to the TextBox using the provider's embedded ErrorProvider component.
The GetRangeInfo helper function returns a control's RangeInfo object or a default object it the control doesn't have an entry.
The AddOrRemoveIfNecessary helper routine compares a RangeInfo object to a default object. If the object has the default values, then the routine ensures that it is removed from the m_RangeInfo hashtable. If the object does not hold the default values, then the routine ensures that it is in the hashtable.
Finally, to help the program decide whether it is safe to exit, the provider includes a HasError function. This function validates all of the registered client controls to display errors for any that are out of range. It then moves focus to the one with the smallest TabIndex value and displays that control's error message in a message box.
|
Imports System.ComponentModel
Imports System.Text.RegularExpressions
<ToolboxBitmap(GetType(IntegerRangeProvider), _
"integer_range_provider.bmp"), _
ProvideProperty("MinValue", GetType(Control)), _
ProvideProperty("MaxValue", GetType(Control)), _
ProvideProperty("RangeFieldName", GetType(Control))> _
Public Class IntegerRangeProvider
Inherits System.ComponentModel.Component
Implements IExtenderProvider
... Component Designer generated code ...
' Information about a control's range.
Private Class RangeInfo
Public MinValue As Integer
Public MaxValue As Integer
Public RangeFieldName As String
Public Sub New()
MinValue = Integer.MinValue
MaxValue = Integer.MaxValue
RangeFieldName = Nothing
End Sub
' Return True if this object represents no range.
Public Function IsDefault() As Boolean
Return (MinValue = Integer.MinValue) And _
(MaxValue = Integer.MaxValue) And _
(RangeFieldName Is Nothing)
End Function
End Class
' The information about fields with ranges.
Private m_RangeInfo As New Hashtable
Private m_Enabled As Boolean = True
<Category("Behavior"), _
DefaultValue(True)> _
Public Property Enabled() As Boolean
Get
Return m_Enabled
End Get
Set(ByVal Value As Boolean)
m_Enabled = Value
End Set
End Property
' We can extend TextBoxes.
Public Function CanExtend(ByVal client_control As _
Object) As Boolean Implements _
IExtenderProvider.CanExtend
Return (TypeOf client_control Is TextBox)
End Function
' Return this control's minimum value.
<Category("Validation"), _
DefaultValue(Integer.MinValue)> _
Public Function GetMinValue(ByVal client_control As _
Control) As Integer
Return GetRangeInfo(client_control).MinValue
End Function
' Set this control's minimum value.
<Category("Validation"), _
DefaultValue(Integer.MinValue)> _
Public Sub SetMinValue(ByVal client_control As Control, _
ByVal min_value As Integer)
' Get this control's range info.
Dim range_info As RangeInfo = _
GetRangeInfo(client_control)
' Set the new minimum value.
range_info.MinValue = min_value
' Add or remove the RangeInfo if necessary.
AddOrRemoveIfNecessary(client_control, range_info)
End Sub
' Return this control's maximum value.
<Category("Validation"), _
DefaultValue(Integer.MaxValue)> _
Public Function GetMaxValue(ByVal client_control As _
Control) As Integer
Return GetRangeInfo(client_control).MaxValue
End Function
' Set this control's maximum value.
<Category("Validation"), _
DefaultValue(Integer.MaxValue)> _
Public Sub SetMaxValue(ByVal client_control As Control, _
ByVal max_value As Integer)
' Get this control's range info.
Dim range_info As RangeInfo = _
GetRangeInfo(client_control)
' Set the new minimum value.
range_info.MaxValue = max_value
' Add or remove the RangeInfo if necessary.
AddOrRemoveIfNecessary(client_control, range_info)
End Sub
' Return this control's error message.
<Category("Validation"), _
DefaultValue("")> _
Public Function GetRangeFieldName(ByVal client_control _
As Control) As String
Return GetRangeInfo(client_control).RangeFieldName
End Function
' Set this control's error message.
<Category("Validation"), _
DefaultValue("")> _
Public Sub SetRangeFieldName(ByVal client_control As _
Control, ByVal error_message As String)
' Get this control's range info.
Dim range_info As RangeInfo = _
GetRangeInfo(client_control)
' Set the new minimum value.
range_info.RangeFieldName = error_message
' Add or remove the RangeInfo if necessary.
AddOrRemoveIfNecessary(client_control, range_info)
End Sub
' A client is validating. See if it is blank.
Private Sub Client_Validating(ByVal sender As Object, _
ByVal e As System.ComponentModel.CancelEventArgs)
If Not m_Enabled Then Exit Sub
ValidateTextBox(DirectCast(sender, TextBox))
End Sub
' Validate the TextBox.
Private Sub ValidateTextBox(ByVal client_control As _
TextBox)
' Get the control's text.
Dim client_text As String = client_control.Text
Dim range_info As RangeInfo = _
GetRangeInfo(client_control)
' See if the text satisfies the range.
If client_text.Length = 0 Then
' It's blank. Allow it.
errOutOfRange.SetError(client_control, "")
Else
' See if it looks like an integer.
Dim r As New Regex("^(-|)[0-9]+$")
If r.Match(client_text).Success Then
' It looks like an integer. Get its value.
Try
Dim client_value As Integer = _
Integer.Parse(client_text)
If client_value < range_info.MinValue _
Then
' Too small.
errOutOfRange.SetError(client_control, _
"Field " & _
range_info.RangeFieldName & " " & _
"must be no smaller than " & _
range_info.MinValue.ToString)
ElseIf client_value > _
range_info.MaxValue Then
' Too big.
errOutOfRange.SetError(client_control, _
"Field " & _
range_info.RangeFieldName & " " & _
"must be no greater than " & _
range_info.MaxValue.ToString)
Else
' Just right.
errOutOfRange.SetError(client_control, _
"")
End If
Catch ex As Exception
' Something weird is going on. Possibly
' this
' value has too many digits for an
' integer.
' Display a generic "bad integer"
' message.
errOutOfRange.SetError(client_control, _
"Field " & _
range_info.RangeFieldName & " must " & _
"be an integer")
End Try
Else
' It doesn't look like an integer.
' Complain.
errOutOfRange.SetError(client_control, _
"Field " & range_info.RangeFieldName & _
" must be an integer")
End If
End If
End Sub
' Return this control's RangeInfo.
Private Function GetRangeInfo(ByVal client_control As _
Control) As RangeInfo
' See if we have RangeInfo for this control.
If m_RangeInfo.Contains(client_control) Then
' We have RangeInfo for this control. Return it.
Return DirectCast(m_RangeInfo(client_control), _
RangeInfo)
Else
' We do not have RangeInfo for this control.
' Return a new default RangeInfo.
Return New RangeInfo
End If
End Function
' Add or remove this RangeInfo if necessary.
Private Sub AddOrRemoveIfNecessary(ByVal client_control _
As Control, ByVal range_info As RangeInfo)
' See if the RangeInfo should be present but is not,
' or should not be present but is.
If range_info.IsDefault <> Not _
m_RangeInfo.Contains(client_control) Then
If range_info.IsDefault Then
' The RangeInfo should not be present but
' is.
m_RangeInfo.Remove(client_control)
RemoveHandler client_control.Validating, _
AddressOf Client_Validating
Else
' The RangeInfo should be present but is
' not.
m_RangeInfo.Add(client_control, range_info)
AddHandler client_control.Validating, _
AddressOf Client_Validating
End If
End If
End Sub
' If some control has an error, display its error
' message,
' set focus to it, and return True. If all controls are
' okay, then return False.
Public Function HasError() As Boolean
If Not m_Enabled Then Return False
' Make sure all controls have been validated.
Dim first_text_box As TextBox = Nothing
Dim first_tab_index As Integer = Integer.MaxValue
For Each text_box As TextBox In m_RangeInfo.Keys
' Validate the TextBox.
ValidateTextBox(text_box)
' See if this is the first in the tab order so
' far.
If errOutOfRange.GetError(text_box).Length > 0 _
Then
If text_box.TabIndex < first_tab_index Then
first_text_box = text_box
first_tab_index = text_box.TabIndex
End If
End If
Next text_box
' See if any control has an error.
If Not (first_text_box Is Nothing) Then
first_text_box.Focus()
MessageBox.Show(errOutOfRange.GetError(first_text_box))
Return True
End If
Return False
End Function
End Class
|