Introduction
When it comes to building a client/server application, one of the most time consuming elements is the GUI. Quite often, a developer will get stuck piecing together the visual elements/appearance with control population, data input validation, and then interaction with the business objects. I struck this very problem while working on our in house systems two years ago. The major bottleneck was validating the input from the user, parsing this data into the business objects, and reporting any/all errors that may occur due to a rule violation. This bottleneck was discovered simply because we were on a fairly strict timeline and some of the forms we had to build were quite large.
My solution was to design and build a textbox control that was:
- Capable of self populating from a business object
- Capable of self validating user input
- Simple to use at design time
- Required very little coding in order to operate
The brief was simple, and it didn't seem too difficult to hit the target...
What was discovered was that with a little bit of perseverance, we actually achieved a suite of controls that are intelligent enough to take care of themselves and allow us developers to get on with the custom coding that actually made the system what it is today.
The SVT control deals with a number of facets of the .NET framework:
- Reflection
- Events
- Shadowing and Overriding
I intend to show the features of this Self Validating TextBox (SVT) control and how its features are implemented and achieved. The article won't actually show how to construct the control as this is not a beginner's article, and this information can be gleaned from the solution example. I have also chosen not to include any screenshots as this control looks no different to a standard TextBox
.
Background
Once the requirements were agreed upon, we consciously decided to make use of a User Control as a "host" for our textbox. We came to this decision because we felt that if the need arose for the control to be inherited for any future requirements, a User Control "environment" would allow this to happen easily, i.e., adding additional controls. This was later proved when we needed to build a "smart" RTF control.
We also decided pretty quickly that we should stick with as many "standard" events, prototypes, properties, etc. where we could. i.e. Validated and TextChanged events; Text, MultiLine properties; These events, prototypes, properties, etc. are drawn from the Windows.Forms.TextBox
control.
This control (and all subsequent) have a very strong link to the business objects they deal with. This was done purposely because we felt that no matter how many degrees of separation you strive for, ultimately, the UI must interact with the business objects. For this reason alone, we decided to try make the text box as aware of the business objects and as intelligent as possible, therefore reducing hand code in the forms.
The SVT control makes reference to code featured in a previous article on Business Object Property Validation.
Structure
Events: The following public events are defined:
Validated(ByVal sender as Object, ByVal e as System.EventArgs)
Public Shadows Event TextChanged(ByVal sender as Object, ByVal e as System.EventArgs)
Public Shadows IsFocused(ByVal sender as Object, ByVal msg as String)
Public Properties: The following public properties are defined:
Public Overridable Shadows Property Text() As String
Public Property ScrollBars() as Windows.Forms.ScrollBars
Public Property PasswordChar() As String
Public Property MultiLine() As Boolean
Public Property AcceptsTab() As Boolean
Public Property AcceptsReturn() As Boolean
Public Overridable Shadows Property ReadOnly() As Boolean
Public Property UseCustomReadOnly() As Boolean
Public Property BizO() As Object
Public Property PropName() As String
Public Property SelfValidate() As Boolean
Public Property SelfPopulate() As Boolean
Public Property SelfValidateAutoEnroll() As Boolean
Public ReadOnly Property ErrorMessage() As String
Public ReadOnly Property DescriptiveText() As String
Public ReadOnly Property DisplayName() As String
Public Property ValidateOnChange() As Boolean
Public Property ValidateOnPopulate() As Boolean
Public Property ValidateOnNoChange() As Boolean
Public Methods: The following public methods are defined:
Public Overridable Shadows Sub Validate()
Public Sub ValueValidate(ByVal strValue As String)
Public Shadows Sub Refresh()
Protected Sub ThrowValidated(ByVal sender As Object, ByVal e As System.EventArgs)
Public Sub Copy()
Public Sub Cut()
Public Sub Paste()
Public Sub Undo()
Public Sub Clear()
Public Sub SelectAll()
Mechanics
At design time, the developer adds the control to a form and then sets its properties to suit. So far, no different from any other control. This, however, is where the SVT control differs. The developer has the ability to decide how the SVT control will behave and react. The majority of properties are already set with defaults. At a minimum, the PropName
property needs to be set. This allows the control to get/set the nominated property from the business object at runtime.
Dealing with the sample form supplied, there is only a single textbox control that requires coding. Again, this is where the SVT control differs as the only code required is as follows:
UITextBox1.BizO = [MyBusinessObject]
Yes!!! That's right. 1 single line of code, unless there is any need for custom validation code in the UI layer.
At runtime, this single line of code, setting the value of the BizO
property, will perform the following actions:
- Set the
Loading
property of the SVT control to True
. This allows for the Validate
event handler to check the ValidateOnPopulate
property and decide whether to continue or not. - Store a reference copy of the business object locally in the SVT control.
- Clear any previous references to old business objects in the SVT control.
- Check to ensure that the current
value
is not null
/Nothing
. - Check to ensure that the
PropName
property is not String.Empty
. - Check the
SelfPopulate
property. If set to True
, read the value from the [PropName]
property in the BizO
object and populate the control.
Again. 1 single line of code to do it.
When the user input is received, the SVT control will perform the following actions:
- Check to ensure the
SelfValidate
property is set to True
and that the BizO
is not null
/Nothing
. - Set the
[PropName]
property in the BizO
object to the value of TextBox.Text
.
Description of Properties
From the list of properties above, it is clear that some of the properties are derived from the Windows.Forms.TextBox
control. All other properties are clarified below:
Public Property UseCustomReadOnly() As Boolean | After initial design and construction, it was determined that our own use of the SVT control should have some sort of overriding mechanism to control how the ReadOnly property is controlled. This is due to the fact that our base forms provide further support for business object integration. For the purposes of this article, this property is redundant, but could be used as and when required. This property can be set at design time. |
Public Property BizO() As Object | The business object. This property stores a local reference copy of the business object being used. This property can only be set at run time. |
Public Property PropName() As String | The name of the property in the business object. This property can be set at design time. |
Public Property SelfValidate() As Boolean | Allows the SVT control to self validate and parse data into the business object. This property can be set at design time. |
Public Property SelfPopulate() As Boolean | Allows the SVT control to populate itself from the business object. This property can be set at design time. |
Public Property SelfValidateAutoEnroll() As Boolean | Our base forms have been extended quite significantly to provide further support for business object integration. As a result, our base forms support a BizO property of their own. When the form BizO property is set, it triggers an iterative process which in turn assigns the BizO property of the controls on the form. This property allows the base form to either assign the value to the control or ignore the control. The property can be set at design time. |
Public ReadOnly Property ErrorMessage() As String | If any errors are encountered during validation, the error message being returned from the business object is stored here. This allows for the control to be more responsible for itself. |
Public ReadOnly Property DescriptiveText() As String | The Description attribute can be applied to properties, and as such, the SVT control can recognise this attribute. So, when the control receives focus, it raises the IsFocused event and parses itself and the value of the Description attribute. |
Public ReadOnly Property DisplayName() As String | Similar to the DescriptiveText property, the DisplayName attribute is defined in the BusinessRules assembly. This allows for the property to be named without having to sacrifice any column/field/property naming convention. |
Public Property ValidateOnChange() As Boolean | Allows for the SVT control to invoke its validation code when the TextChanged event is raised. This property can be set at design time. |
Public Property ValidateOnPopulate() As Boolean | Allows for the SVT control to invoke its validation code when the control is populated by way of the BizO property. This property can be set at design time. |
Public Property ValidateOnNoChange() As Boolean | Allows for the SVT control to invoke its validation code when no changes have been made. This property can be set at design time. |
Validation
The main focus of the SVT control initially was the validation aspect.
Protected Overridable Sub EditBox_Validated(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles EditBox.Validated
If ValidateOnNoChange = False And mBlnHasChanged = False Then Return
If MyClass.SelfValidate And Not BizO Is Nothing Then
Dim txt As Windows.Forms.TextBox = CType(sender, Windows.Forms.TextBox)
Try
BizoSetValue(txt.Text)
If mBlnHasChanged = True Then mStrErrMsg = String.Empty
Catch ex As Exception
If Not ex.InnerException Is Nothing Then
mStrErrMsg = ex.InnerException.Message
Else
mStrErrMsg = ex.Message
End If
Finally
Dim obj() As Object = {Me, ErrorMessage}
mObjMeth.Invoke(BizO, obj)
mBlnHasChanged = False
End Try
End If
RaiseEvent Validated(Me, e)
End Sub
As you can see from the above code, the validation routine checks the ValidateOnNoChange
and SelfValidate
properties. Once all conditions have been satisfied, the BizoSetValue
protected method is then called:
Protected Sub BizoSetValue(ByVal value As Object)
If BizO Is Nothing Then Return
If Loading = True Then Return
If CType(BizO, BusinessBase).UsingCProps Then
CType(BizO, BusinessBaseCProps).Prop(MyClass.PropName, value)
Else
If PropertyObject Is Nothing Then Return
If PropertyObject.CanWrite Then PropertyObject.SetValue(BizO, value, Nothing)
End If
End Sub
The BizoSetValue
method also checks to ensure that the property in the business object (PropertyObject
) being referenced actually exists and can be written to. The method then checks the type of business object in use, and sets the value accordingly. Referenced within is a reference to PropertyObject
:
Protected ReadOnly Property PropertyObject() As Object
Get
If mObjProp Is Nothing Then
If BizO Is Nothing Then Return Nothing
If PropName.Equals(String.Empty) Then Return Nothing
If CType(BizO, BusinessBase).UsingCProps Then
mObjProp = CType(BizO, BusinessBaseCProps).VTType.GetField(MyClass.PropName)
Else
mObjProp = BizO.GetType.GetProperty(MyClass.PropName)
End If
End If
Return mObjProp
End Get
End Property
Conclusion
I hope the above has provided you with enough of an insight into the SVT control. After the initial design and construction of this control, it was evident that we needed to extend the idea of a self validating control to other more common controls. This need grew into a CheckBox, NumericBox (textbox with numeric input only), DateCombo, ComboBox, and RichTextBox.
Our base forms were then looked at in the interest of continuity and rapid development. These base forms were modified to include OK, Cancel, and Apply functionality. This functionality makes use of the BizO
object, and allows for very minimal code to be written while still providing fully featured forms. The only need for custom coding is where custom functionality is required. Our in house application has now been in production use for more than two years, and is continually being added to, providing further support and enhancements.
Originally, we were a little skeptical about the use of reflection and how it may sluggish performance. Our other major concern was a potentially larger memory footprint and hence further memory related issues. To date, we haven't experienced any performance or memory issues, and some of the forms that have been developed are quite large and complex in nature.
Future Updates
It seems that this article and the Business Object Property Validation article have had a natural flow from each other. With this in mind, I intend to produce additional articles detailing some of the questions that I'm sure will come from these two, like:
- What does the BusinessRules assembly do?
- How have the base forms been designed and constructed?
- What other controls have been produced and how?
- How does this article relate to a real world n-tier solution?
Please enjoy.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.