Author Topic: Error checking controls on form  (Read 6614 times)

0 Members and 1 Guest are viewing this topic.

David Hall

  • Automatic Duh Generator
  • King Gator
  • Posts: 4076
Error checking controls on form
« on: January 06, 2009, 10:28:17 AM »
What is the best way to error check that a user has populated all controls on a form?  I have 4 controls that I wish to make sure are populated, and the best I can come up with is nested IFs which are a huge pain in the neck.  Any ideas or suggestions that you guys use?
Everyone has a photographic memory, Some just don't have film.
They say money can't buy happiness, but it can buy Bacon and that's a close second.
Sometimes the question is more important than the answer. (Thanks Kerry for reminding me)

David Hall

  • Automatic Duh Generator
  • King Gator
  • Posts: 4076
Re: Error checking controls on form
« Reply #1 on: January 06, 2009, 10:28:48 AM »
Forgot to mention, written in C#
Everyone has a photographic memory, Some just don't have film.
They say money can't buy happiness, but it can buy Bacon and that's a close second.
Sometimes the question is more important than the answer. (Thanks Kerry for reminding me)

sinc

  • Guest
Re: Error checking controls on form
« Reply #2 on: January 06, 2009, 10:41:42 AM »
You might want to look at the ErrorProvider component.  Simply add it to your form, and you get a variety of controls.  Then add code to handle the "Validating" and "Validated" events for various fields as-necessary.  This functionality is built-in to Designer.

There are also some downloads that can make this easier, so you don't have to manually create the "Validating" and "Validated" event handlers, and can instead simply set properties in Designer.  I'm not sure what's best among those, though.

David Hall

  • Automatic Duh Generator
  • King Gator
  • Posts: 4076
Re: Error checking controls on form
« Reply #3 on: January 06, 2009, 10:53:54 AM »
thanks
Everyone has a photographic memory, Some just don't have film.
They say money can't buy happiness, but it can buy Bacon and that's a close second.
Sometimes the question is more important than the answer. (Thanks Kerry for reminding me)

Ken Alexander

  • Newt
  • Posts: 61
Re: Error checking controls on form
« Reply #4 on: January 06, 2009, 11:17:34 AM »
The ErrorProvider Class implements IExtenderProvider; you might look into this Interface if the ErrorProvider Class doesn't meet your needs.
Ken Alexander

David Hall

  • Automatic Duh Generator
  • King Gator
  • Posts: 4076
Re: Error checking controls on form
« Reply #5 on: January 06, 2009, 01:49:37 PM »
the error provider is working, but my question is do I have 1 for each control or can I tie 4 controls to 1 provider
Everyone has a photographic memory, Some just don't have film.
They say money can't buy happiness, but it can buy Bacon and that's a close second.
Sometimes the question is more important than the answer. (Thanks Kerry for reminding me)

sinc

  • Guest
Re: Error checking controls on form
« Reply #6 on: January 06, 2009, 02:28:14 PM »
One provider for each form.

Then create "Validating" and/or "Validated" event handlers for each field you want to validate - in designer, you can switch to "Events" in properties view and double-click on an event to create the code stub-out.  In the event handlers, use the errorProvider.SetError() method to control the error indicator to display in the form.

If you want to keep the user from leaving a field until a correct value is entered, set the "Cancel" property in the EventArgs for the "Validating" event handler.

David Hall

  • Automatic Duh Generator
  • King Gator
  • Posts: 4076
Re: Error checking controls on form
« Reply #7 on: January 06, 2009, 04:03:35 PM »
OK, that makes sense, now to see if I can do it.
Everyone has a photographic memory, Some just don't have film.
They say money can't buy happiness, but it can buy Bacon and that's a close second.
Sometimes the question is more important than the answer. (Thanks Kerry for reminding me)

Spike Wilbury

  • Guest

TonyT

  • Guest
Re: Error checking controls on form
« Reply #9 on: January 07, 2009, 12:19:31 PM »
The ErrorProvider Class implements IExtenderProvider; you might look into this Interface if the ErrorProvider Class doesn't meet your needs.

I'm not sure what you're getting at.

IExtenderProvider is for dynamically adding 'pseudo-properties' to
controls in the designer, like the ones the ErrorProvider adds.

It has nothing to do with validation.

Ken Alexander

  • Newt
  • Posts: 61
Re: Error checking controls on form
« Reply #10 on: January 07, 2009, 04:07:29 PM »
The ErrorProvider Class implements IExtenderProvider; you might look into this Interface if the ErrorProvider Class doesn't meet your needs.

I'm not sure what you're getting at.

IExtenderProvider is for dynamically adding 'pseudo-properties' to
controls in the designer, like the ones the ErrorProvider adds.

It has nothing to do with validation.

My point is that you can create your own robust “ErrorProvider” or “ValidationTool”, whatever you want to call it, by using IExtenderProvider.  I created a simple down and dirty example called TextBoxValidator.

When using the ErrorProvider you have to write each control’s validation logic in the controls validation event or somewhere else.  By using the IExtenderProvider you can create a component that you can drop on a form that adds your ‘pseudo-properties’ to each control that this extender can extend.  With these properties you can then set each control’s validation at design time and your custom Validator knows what to do with it.

The sample below demonstrates a custom TextBoxValidator.  After droping this component onto a form, all textboxes will have a new property called “ValidationType on TextBoxValidator1”

You could also very easily extend .NETs ErrorProvider class using the TextBoxValidator code so the little icon and error messages are displayed.

Code: [Select]

Imports System.ComponentModel

<ProvideProperty("ValidationType", GetType(TextBox))> _
Public Class TextBoxValidator
    Inherits Component
    Implements IExtenderProvider

    Private _Validations As New Dictionary(Of TextBox, ValidationType)
    Private _AllowValidation As Boolean = True

    Public Property AllowValidation() As Boolean
        Get
            Return _AllowValidation
        End Get
        Set(ByVal value As Boolean)
            _AllowValidation = value
        End Set
    End Property

    Public Function CanExtend(ByVal extendee As Object) As Boolean Implements System.ComponentModel.IExtenderProvider.CanExtend
        If TypeOf extendee Is TextBox Then
            Return True
        End If
    End Function

    Public Function GetValidationType(ByVal txtBox As TextBox) As ValidationType
        If _Validations.ContainsKey(txtBox) Then
            Return _Validations(txtBox)
        Else
            Return ValidationType.None
        End If
    End Function

    Public Sub SetValidationType(ByVal txtBox As TextBox, ByVal value As ValidationType)
        Dim ValidationType As ValidationType = value
        If _Validations.ContainsKey(txtBox) Then
            _Validations(txtBox) = value
        Else
            _Validations.Add(txtBox, value)
        End If
        Select Case ValidationType
            Case ValidationType.None
                RemoveHandler txtBox.Validating, AddressOf TextBoxValidating
            Case Else
                AddHandler txtBox.Validating, AddressOf TextBoxValidating
        End Select
    End Sub

    Private Sub TextBoxValidating(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs)
        Dim Flag As Boolean
        Dim txtBox As TextBox = DirectCast(sender, TextBox)
        If AllowValidation Then
            Select Case _Validations(txtBox)
                Case ValidationType.RequireInput
                    If txtBox.Text.Trim = "" Then
                        Flag = True
                    Else
                        Flag = False
                    End If
                Case ValidationType.RequireInteger
                    Dim Result As Integer
                    If Integer.TryParse(txtBox.Text, Result) Then
                        Flag = False
                    Else
                        Flag = True
                    End If
                Case Else
                    Flag = False
            End Select
            If Flag Then
                txtBox.BackColor = Color.Red
            Else
                txtBox.BackColor = Color.White
            End If
        End If
    End Sub
End Class

Public Enum ValidationType
    None
    RequireInput
    RequireInteger
End Enum


« Last Edit: January 07, 2009, 07:04:59 PM by Ken Alexander »
Ken Alexander

TonyT

  • Guest
Re: Error checking controls on form
« Reply #11 on: January 08, 2009, 10:27:26 AM »
Well yes, you can do that, but I can't see any useful purpose
to it, because the use of data binding eliminates the need for it,
and allows you to do much more with little work.

I routinely use data binding to bind controls to properties of a
class, which gives me much greater control over validation and
formatting.

This sample shows that, and why there's no need for taking
the kind of approach you suggest:

  http://www.caddzone.com/DataBindingSample.zip

If you download and run the sample app and type 'ABC' in the
'Effective Height' TextBox and press the TAB key, you'll see why
IExtenderProvider is not needed to do robust validation.


The ErrorProvider Class implements IExtenderProvider; you might look into this Interface if the ErrorProvider Class doesn't meet your needs.

I'm not sure what you're getting at.

IExtenderProvider is for dynamically adding 'pseudo-properties' to
controls in the designer, like the ones the ErrorProvider adds.

It has nothing to do with validation.

My point is that you can create your own robust “ErrorProvider” or “ValidationTool”, whatever you want to call it, by using IExtenderProvider.  I created a simple down and dirty example called TextBoxValidator.

When using the ErrorProvider you have to write each control’s validation logic in the controls validation event or somewhere else.  By using the IExtenderProvider you can create a component that you can drop on a form that adds your ‘pseudo-properties’ to each control that this extender can extend.  With these properties you can then set each control’s validation at design time and your custom Validator knows what to do with it.

The sample below demonstrates a custom TextBoxValidator.  After droping this component onto a form, all textboxes will have a new property called “ValidationType on TextBoxValidator1”

You could also very easily extend .NETs ErrorProvider class using the TextBoxValidator code so the little icon and error messages are displayed.

Code: [Select]

Imports System.ComponentModel

<ProvideProperty("ValidationType", GetType(TextBox))> _
Public Class TextBoxValidator
    Inherits Component
    Implements IExtenderProvider

    Private _Validations As New Dictionary(Of TextBox, ValidationType)
    Private _AllowValidation As Boolean = True

    Public Property AllowValidation() As Boolean
        Get
            Return _AllowValidation
        End Get
        Set(ByVal value As Boolean)
            _AllowValidation = value
        End Set
    End Property

    Public Function CanExtend(ByVal extendee As Object) As Boolean Implements System.ComponentModel.IExtenderProvider.CanExtend
        If TypeOf extendee Is TextBox Then
            Return True
        End If
    End Function

    Public Function GetValidationType(ByVal txtBox As TextBox) As ValidationType
        If _Validations.ContainsKey(txtBox) Then
            Return _Validations(txtBox)
        Else
            Return ValidationType.None
        End If
    End Function

    Public Sub SetValidationType(ByVal txtBox As TextBox, ByVal value As ValidationType)
        Dim ValidationType As ValidationType = value
        If _Validations.ContainsKey(txtBox) Then
            _Validations(txtBox) = value
        Else
            _Validations.Add(txtBox, value)
        End If
        Select Case ValidationType
            Case ValidationType.None
                RemoveHandler txtBox.Validating, AddressOf TextBoxValidating
            Case Else
                AddHandler txtBox.Validating, AddressOf TextBoxValidating
        End Select
    End Sub

    Private Sub TextBoxValidating(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs)
        Dim Flag As Boolean
        Dim txtBox As TextBox = DirectCast(sender, TextBox)
        If AllowValidation Then
            Select Case _Validations(txtBox)
                Case ValidationType.RequireInput
                    If txtBox.Text.Trim = "" Then
                        Flag = True
                    Else
                        Flag = False
                    End If
                Case ValidationType.RequireInteger
                    Dim Result As Integer
                    If Integer.TryParse(txtBox.Text, Result) Then
                        Flag = False
                    Else
                        Flag = True
                    End If
                Case Else
                    Flag = False
            End Select
            If Flag Then
                txtBox.BackColor = Color.Red
            Else
                txtBox.BackColor = Color.White
            End If
        End If
    End Sub
End Class

Public Enum ValidationType
    None
    RequireInput
    RequireInteger
End Enum



Ken Alexander

  • Newt
  • Posts: 61
Re: Error checking controls on form
« Reply #12 on: January 08, 2009, 06:22:05 PM »
If you don’t see any useful purpose in a component that implements IExtenderProvider as a validation tool, then why are you using one in your data binding example? 

In reality data binding has absolutely nothing to do with Form validation and IExtenderProvider is the KEY to it.  Your sample is a data binding example that shows appropriate business logic validation not a re-usable, extendable Form validation tool.

If you take the sample component I provided and drop it on ANY form you may have and select ANY TextBox then go to the properties window and set that TextBox’s ValidationType to “RequireInteger”, that TextBox is going to require an integer, no class to make, no data source to set up, no matching Properties to worry about, no Property mapping to do, just one simple property to change at design time and you’re done.  My sample turns the TextBox red if it isn’t an Integer though I could have just as easily forced focus on the TextBox.  Each TextBox validation can behave in as many different ways as you have EXTENDED their capabilities.  To me, that’s the makings of a robust Form validation tool. And better yet, down the road, if you end up with data bound controls, it’ll work with them too.
Ken Alexander

TonyT

  • Guest
Re: Error checking controls on form
« Reply #13 on: January 09, 2009, 03:07:51 PM »
If you don’t see any useful purpose in a component that implements IExtenderProvider as a validation tool, then why are you using one in your data binding example? 


I'm not using any IExtenderProviders that do validation.

Where did you get that idea from? 

ErrorProvider is an IExtenderProvider, but it does not do
any kind of validation.

You seem to have misunderstood what I typed, so let me be
more specific:

I don't see any useful purpose to using IExtenderProvider to
do what your example does.  If you do things the correct way,
via the mechanisms provided by the framework, rather than
take a 'roll-your-own' approach, then point in fact is that the
example you show serves no purpose, because the information
that it associates with each control is already inferred by the
type of the property which the control is bound to.

If I databind a control to a property whose type is an integer,
the framework knows that the input must be convertable to an
integer, and it will do the conversion for me, and raise the error
that occurs if the contents of the text box is not convertable
to an integer.  So, given that the framework does all of that for
me when I do things the right way (data binding), why do I need
to associate another 'extended property' with a control that does
nothing other than indicate that the control requires an integer?

In the case of using data binding to an integer property of an
object, the framework already knows the control requires an
integer, because that is the type of the property the control
is bound to. Additional data validation is done by the setter of
the bound property, because in most cases, that validation is
something that applies not only to user-input, but also to any
value the property is set to, via any means, including consumer
code.


Quote

In reality data binding has absolutely nothing to do with Form
validation...


That's simply not true.

I don't see how anyone can make a statement like that, given
that the data binding sample that I posted the link to contains
no code that performs the basic validation required in order to
convert the user-supplied text to the required data type (ints
and doubles). That is (the most basic) form of 'validation'.

Your example IExtenderProvider is absurd, because you still
have to do the basic validation/conversion yourself in code,
rather than allowing the framework to do it for you, as it
does when using data binding.

At this point I have to bow out of this conversation, because
it's beginning to resemble a dead horse-beating contest.

« Last Edit: January 09, 2009, 05:02:38 PM by TonyT »

Ken Alexander

  • Newt
  • Posts: 61
Re: Error checking controls on form
« Reply #14 on: January 09, 2009, 07:57:57 PM »
Fair enough.  I will bow out with my final words.

You are right; the ErrorProvider does not do any validation.  It requires you to re-enter validation code for every control in every form you want to validate.  Your data binding method requires basically the same.

To say that the data binding is a better approach because the framework is handling basic validation (String to Integer).  Come on, that’s casting/converting not validation.  Whether the binding casts it for me or I use a TryParse, it’s still casting (I wonder what the IL code would show?)  Both of our methods require us to write our own validation, who else is going to?

Bottom line is my method isn't in theory, its in practice, works quite nicely, and is as handy as a shirt pocket.

Ken Alexander

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Error checking controls on form
« Reply #15 on: January 09, 2009, 08:16:47 PM »

Just to take the heat out of this .. or redirect it ;

It's my understanding that the databinding of a control enforces the type conformance.

.. and that any other validation ( usually based on business rules) should be done via a specific callback.
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

sinc

  • Guest
Re: Error checking controls on form
« Reply #16 on: January 09, 2009, 08:37:25 PM »
Validation in the business rules can be re-used, regardless of the interface.

Say you initially create a Forms interface to part of your program.  Then later, you also want to add a web interface.  If your validation is in the business objects, it does not have to be redone for the web interface.  However, if you are validating in your interface, you have to make sure every interface does the correct validation.

Of course, this can be colored by other factors.  For example, validation in a web interface may be desirable, because validation in the business objects may require a request be sent to the server.  Meanwhile, validation in the interface can happen immediately, on the client side.

TonyT

  • Guest
Re: Error checking controls on form
« Reply #17 on: January 10, 2009, 01:26:21 PM »
Data binding can only validate the formatting of textual input, it can't
do any other kind of validation.

In the case of binding to properties of objects (as opposed to binding
to fields of a database record, for example), a property's setter must
usually validate the value it is given in any case, regardless of whether
the value is being set by data binding, or by other consumer code.

The point here is that it is counter-productive to couple code that
does validation, to specific controls, namely because there are many
scenarios where one might want to present data in different ways,
like for example, you may want to offer the user a 'form view' or you
may want to offer them a 'tablular' view where the values appear in a
single row of a DataGridView, or you may want to present the values
in a property grid.

If the validation code is placed in handlers of control events on
a form, then how can one easily reuse that code to do the same
validation when the same data is presented in a data grid row, or
in a property grid?

So, that's the problem with Ken's approach.

You can't easily change how you present data, and/or present it in
multiple or different ways, if you couple the validation code directly
to the user interface or to user interface controls.


Just to take the heat out of this .. or redirect it ;

It's my understanding that the databinding of a control enforces the type conformance.

.. and that any other validation ( usually based on business rules) should be done via a specific callback.

« Last Edit: January 10, 2009, 01:34:11 PM by TonyT »

TonyT

  • Guest
Re: Error checking controls on form
« Reply #18 on: January 10, 2009, 01:37:27 PM »
Right. And validation can be done both at the client and at the server.

If for example, a value must be unique, the data set that it must be
tested against for uniqueness may be quite large, and that means
the validation would need to happen on the server, where the data is.

Validation in the business rules can be re-used, regardless of the interface.

Say you initially create a Forms interface to part of your program.  Then later, you also want to add a web interface.  If your validation is in the business objects, it does not have to be redone for the web interface.  However, if you are validating in your interface, you have to make sure every interface does the correct validation.

Of course, this can be colored by other factors.  For example, validation in a web interface may be desirable, because validation in the business objects may require a request be sent to the server.  Meanwhile, validation in the interface can happen immediately, on the client side.

TonyT

  • Guest
Re: Error checking controls on form
« Reply #19 on: January 10, 2009, 08:54:43 PM »

You are right; the ErrorProvider does not do any validation.  It requires you to re-enter validation code for every control in every form you want to validate.  Your data binding method requires basically the same.


Sorry, that's just not the case. :roll:

The data binding method does not require me to write any code to
validate the input text and convert it to the input data type.

That's about it for me.

Ken Alexander

  • Newt
  • Posts: 61
Re: Error checking controls on form
« Reply #20 on: January 12, 2009, 05:57:41 PM »
Let’s get down to the real nuts and bolts here. 

First of all, in both examples, the validation was written in private methods specific to the examples.  I know I did this, and I’m quite certain Tony did to, for readability.  Typically all of this type of validation or logic would be contained as shared methods of a class.  The validation method can be used anywhere, in a single controls event, in a Properties setter, or in a component such as mine that automatically creates the link between the validation method and control event.  So it is safe to say that with either method chosen for validation, the actual validation code is written only once and can be used anywhere.

Second, let’s look at the responsibility of validation.  Let’s say we have two vendors, both are giving us an employee object to work with.  Well Vendor A decided to put logic in the setter of the Employee phone number property to force a string that looks like: “(555) 123-1234” while Vendor B only required the property to be a string.  What vendor am I going to choose?  Before I answer, let’s look at something else.  This same employee object has another property called Experience of type Integer.  Vendor B assumed, that for obvious reasons, no one would hire somebody with zero experience so he decided to put validation in the setter of the Experience property to prevent a value less than one.  Worse yet, an exception is thrown if the value is less than one.  I’m thinking to myself, the property is asking for an Integer, I’m giving it an Integer, why the exception (put that in a 1000 iteration loop and you’ll see what I mean)?  I’m going to choose Vendor B because I want my phone numbers to look like: “555-123-1234” and I might want to hire someone with zero experience.  So it is also safe to say that much of the input validation and formatting will happen at different tiers of an application.

Third, data binding is great for its intended purpose, to link control values to some form of data source.  The framework also gives you the means to do validating between your data and visual controls.  That means you may be required to put more rules on a property than you should.  From what I have read, I didn’t see it in Tony’s example, that the framework also provides you with two events, Format and Parse, which you can use to help with formatting of data bound controls.  Data binding has been around long before you had the ability to bind to a custom object so I doubt the intent of data binding was to perform proper form validation.

Finally, let’s get back to the OP’s original question and quit trying to shoot holes in a method you must not understand.  He’s not asking the best approach in engineering an N-Tier application.  He’s asking what is the best way to error check that a user has populated all controls on a form.  Are you saying that your answer to him would be to look at your data binding example for the answer?
Ken Alexander