Solved

Control Validation Simple

Posted on 2010-09-23
11
402 Views
Last Modified: 2013-12-16
Experts,

I`m using VS 2008 C# 3.5, Windows Forms    

I`m trying to validate some controls. For the sake of simlicity I`m using two text boxes as an example here. When the text boxes are validated either at the ValidateForm() method or the TextBox_leave event the values are assigned [HStart and HEnd]. Then I need to check some conditions based on the HStart and the HEnd values, the way I`m doing it right now is in ValidateForm() method. I would like to do this condition check in the HStartValidate() or HEndValidate() itself so that these are called when the focus leaves the Textboxes.
   
The way it is structured right now is a two tier validation. Validate and assign values, and then do another validation based on the assigned values. Can I make this into a single tier, a more concise and better way to do it. If you have a 20-30 text boxes, this just becomes too hard to manage.
   
    Here is the code.
     
       
       
        //Start
        private double hStart = Settings.Default.HFibStartSet;
        public double HStart
        {
            get
            {
                return hStart;
            }
            set
            {
                hStart = value;
            }
        }

        public String HStartTB
        {
            get
            {
                return HStartTBox.Text;
            }
            set
            {
                HStartTBox.Text = value;
            }
        }

        private bool HStartValidate(UnitsClass.UClass UnitObj)
        {
            if (HStartTB.Length <= 0)
            {
                ErrProXUserCntrl.SetError(HStartTBox, "Enter the  Start Position");
                return false;
            }
            else if (Convert.ToDouble(HStartTB) < (GlobalParam.LowLim * UnitObj.UnitConv) || Convert.ToDouble(HStartTB) > (GlobalParam.HighLim * UnitObj.UnitConv))
            {
                ErrProXUserCntrl.SetError(HStartTBox, "Out of Bounds!  start position should be between " + (GlobalParam.LowLim * UnitObj.UnitConv) + UnitObj.UnitStr + " and " + (GlobalParam.HighLim * UnitObj.UnitConv) + UnitObj.UnitStr);
                return false;
            }
            else
            {
                HStart = Convert.ToDouble(HStartTB);
                ErrProXUserCntrl.SetError(HStartTBox, String.Empty);
                return true;
            }
        }

        private void HStartTBox_Leave(object sender, EventArgs e)
        {
            HStartValidate(UnitsClass.GetUnits(XMetricUserCntrl.MetricFlag));
        }

        //End
        private double hEnd = Settings.Default.HFibEndSet;
        public double HEnd
        {
            get
            {
                return hEnd;
            }
            set
            {
                hEnd = value;
            }
        }

        public String HEndTB
        {
            get
            {
                return HEndTBox.Text;
            }
            set
            {
                HEndTBox.Text = value;
            }
        }

        private bool HEndValidate(UnitsClass.UClass UnitObj)
        {
            if (HEndTB.Length <= 0)
            {
                ErrProXUserCntrl.SetError(HEndTBox, "Enter the  End Position");
                return false;
            }
            else if (Convert.ToDouble(HEndTB) < (GlobalParam.DumVarOne * UnitObj.UnitConv) || Convert.ToDouble(HEndTB) > (GlobalParam.DumVarTwo * UnitObj.UnitConv))
            {
                ErrProXUserCntrl.SetError(HEndTBox, "Out of Bounds!  end position should be between " + (GlobalParam.DumVarOne * UnitObj.UnitConv) + UnitObj.UnitStr + " and " + (GlobalParam.DumVarTwo * UnitObj.UnitConv) + UnitObj.UnitStr);
                return false;
            }
            else
            {
                HEnd = Convert.ToDouble(HEndTB);
                ErrProXUserCntrl.SetError(HEndTBox, String.Empty);
                return true;
            }
        }

        private void HEndTBox_Leave(object sender, EventArgs e)
        {
            HEndValidate(UnitsClass.GetUnits(XMetricUserCntrl.MetricFlag));
        }
       
       
        //Validation Function
        public bool ValidateForm()
        {
            List<bool> XParamErrorBoolList = new List<bool>();
           
            XParamErrorBoolList.Add(HStartValidate(UCObj));
            XParamErrorBoolList.Add(HEndValidate(UCObj));

            if (XParamErrorBoolList.All(X => X))
            {
                bool VBool = false;

                if (HStart > HEnd)
                {
                    ErrProXUserCntrl.SetError(HStartTBox, "Start position cannot be greater than than the end position");
                }
                else
                {
                    VBool = true;
                }

                return VBool;
            }
            else
            {
                return false;
            }
        }

Ideas and suggestions are greatly appreciated.

Best,
San
       
0
Comment
Question by:San24
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 5
11 Comments
 
LVL 16

Expert Comment

by:kris_per
ID: 33747925

TextBox itself is having an 'Validating' event. If validation is ok, then you can allow the focus to leave the control. If not valid, then you can cancel the leaving and focus will remain in the textbox. See if using 'Validating' event will solve your issue...

=> http://msdn.microsoft.com/en-us/library/system.windows.forms.control.validating(VS.71).aspx
0
 

Author Comment

by:San24
ID: 33747992
@Kris - I`ve used Validating events in the past, I don`t want to cancel the event. Leave event works better.
0
 
LVL 16

Accepted Solution

by:
kris_per earned 500 total points
ID: 33748306

Better way is to move all the validation logic to a common class and use that common class in both the places.

Assign a tag to each textbox like:
textBoxName.Tag = "Name";
textBoxAge.Tag = "Age";

Have a business object that will store the values of all 20 textboxes.
For example:
public class Person
{

      public string Name;
      public string Age;        
      // etc
}

Update the fields of this Person object when user changes values in textboxes

Direct all your leave or validating events to single method like:
textBoxName.Leave += new EventHandler(TextBox_Leaving);
textBoxAge.Leave += new EventHandler(TextBox_Leaving);

In the common leaving method:
private void TextBox_Leaving(object sender, EventArgs e)
{
   TextBox textBox = (TextBox)sender;

   ValidationProvider.Validate(textBox.Text, textBox.Tag, person);
}

public bool ValidateForm()
{
    ValidationProvider.Validate(textBoxName.Text, textBoxName.Tag, person);
    ValidationProvider.Validate(textBoxAge.Text, textBoxAge.Tag, person);
}

////////////////////////////////


public class ValidationProvider
{
   public static bool Validate(string value, string fieldTag, Person person)
   {
         if(fieldTag == "Name")
         {
             // 'value' is Name; validate it
             // use other field values from person object if needed
         }
         else if(fieldTag == "Age")
         {
             // validate Age whose value is in 'value'
         }
   }

}

Having a common class for validation will help to reuse in any number of places.

You final solution need not to be exactly like this. You may need to make changes to suit your code.  But I Hope this gives you some idea on how or what you can do to make it better.

0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:San24
ID: 33748485
@Kris - Trying your approach now.
0
 
LVL 16

Expert Comment

by:kris_per
ID: 33752649

I got some working code for simplified validation...Hope this helps...
using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace WindowsFormsApplication4
{
    public partial class Form7 : Form
    {
        private Position _position = new Position();

        public Form7()
        {
            InitializeComponent();

            textBoxStartPos.Tag = "StartPos";
            textBoxEndPos.Tag = "EndPos";

            this.textBoxStartPos.Leave += new System.EventHandler(this.textBox_Leave);
            this.textBoxEndPos.Leave += new System.EventHandler(this.textBox_Leave);

            this.textBoxStartPos.TextChanged += new System.EventHandler(this.textBoxStartPos_TextChanged);
            this.textBoxEndPos.TextChanged += new System.EventHandler(this.textBoxEndPos_TextChanged);
        }

        private void textBoxStartPos_TextChanged(object sender, EventArgs e)
        {
            double start = 0;

            double.TryParse(textBoxStartPos.Text, out start);

            _position.Start = start;
        }

        private void textBoxEndPos_TextChanged(object sender, EventArgs e)
        {
            double end = 0;

            double.TryParse(textBoxEndPos.Text, out end);

            _position.End = end;
        }

        private void textBox_Leave(object sender, EventArgs e)
        {
            TextBox textBox = (TextBox)sender;

            List<string> errors = ValidationProvider.Validate(_position, textBox.Tag as string);

            HandleErrors(errors);
        }

        private void buttonValidateForm_Click(object sender, EventArgs e)
        {
            ValidateForm();
        }

        public void ValidateForm()
        {   
            List<string> allErrors = ValidationProvider.Validate(_position, ""); // pass empty string for fieldtag to validate all fields

            HandleErrors(allErrors);
        }

        private void HandleErrors(List<string> errors)
        {
            if (errors.Count > 0)
            {
                // process errors as required 
                // for example show them in another control
                // OR .net has ErrorProvider control which can be used
                // to show a red warning circle near the control having the error.

                textBoxErrors.Lines = errors.ToArray(); // textBoxErrors.Multiline is set to true
            }
            else
            {
                textBoxErrors.Text = "";
            }
        }
    }
}

///////////////////////////////////////////////////
ValidationProvider.cs

using System.Collections.Generic;

namespace WindowsFormsApplication4
{
    public class Position
    {
        public double Start;
        public double End;
    }

    public class ValidationProvider
    {
        public static List<string> Validate(Position position, string fieldTag)
        {
            // if fieldTag is empty or null, then it means validate whole form;
            // otherwise validate only the field specified by the fieldTag

            bool validateAll = string.IsNullOrEmpty(fieldTag);

            List<string> errors = new List<string>();

            if (fieldTag == "StartPos" || validateAll)
            {
                ValidateStartPos(position, errors);
            }

            if (fieldTag == "EndPos" || validateAll)
            {
                ValidateEndPos(position, errors);
            }

            if (validateAll)
            {
                // any common validation here
            }

            return errors;
        }

        public static void ValidateStartPos(Position position, List<string> errorList)
        {
            if (position.Start == 0)
            {
                errorList.Add("Start Position must have value");
            }
            else if (position.Start < 50 || position.Start > 100)
            {
                errorList.Add("Start Position must be between 50 and 100");
            }
            else if (position.Start > position.End)
            {
                errorList.Add("Start position cannot be greater than End position");
            }
        }

        public static void ValidateEndPos(Position position, List<string> errorList)
        {
            if (position.End == 0)
            {
                errors.Add("End Position must have value");
            }
            else if (position.End < 50 || position.End > 100)
            {
                errors.Add("End Position must be between 50 and 100");
            }
            else if (position.End < position.Start)
            {
                errors.Add("End position cannot be lesser than Start position");
            }
        }
    }
}

Open in new window

0
 

Author Comment

by:San24
ID: 33754704
@ Kris .. Thanks for the code. I tried your code. First thing I notices was, if the StartPos text box has a value and the EndPos doesn`t have a value, the condition (position.Start > position.End) is passing, eventhough Position.End doesn`t have a value. But it doesn`t happen the other way i.e, when EndPos has a value and StartPos doesn`t. Doesn`t make sense.
0
 
LVL 16

Assisted Solution

by:kris_per
kris_per earned 500 total points
ID: 33754903

Then changing the condition to as following will make it fine..
...
else if (position.Start > position.End && position.End > 0)
            {
                errorList.Add("Start position cannot be greater than End position");
            }

> But it doesn`t happen the other way
The reason for this is - StartPos is 0 which is already lesser than EndPos.
0
 
LVL 16

Expert Comment

by:kris_per
ID: 33755224

If 0 is a valid value, then you need to do something more like:

Use the value of -1 for 'user has not entered value' condition. Initialize Start and End values to -1 in Position class and in TextChanged events, if the entered value is not a valid number, then reset values to -1. Use this -1 value in Validate methods to identify, user hasn't entered any valid value.

Another option is to use nullable double types (like public double? Start;), where double can be set to null and use null value 'user has not entered value' condition.
0
 
LVL 16

Assisted Solution

by:kris_per
kris_per earned 500 total points
ID: 33755255

As I said, it need not to be exactly as I have mentioend. You can extend or cut as to fit your requirement. But having separate validation class taking a business object (like Position) will make it work better and easy to maintain the code for larger validations...
0
 

Author Comment

by:San24
ID: 33755263
@Kris - Thats what I was thinking too, use a double? cause 0 is valid and you cannot use other values cause the boundary conditions will be checked. I`m trying to customize the approach to my needs, I`ll keep you updated.
0
 

Author Closing Comment

by:San24
ID: 33899134
Solution reached.
0

Featured Post

How our DevOps Teams Maximize Uptime

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us. Read the use case whitepaper.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Introduction Hi all and welcome to my first article on Experts Exchange. A while ago, someone asked me if i could do some tutorials on object oriented programming. I decided to do them on C#. Now you may ask me, why's that? Well, one of the re…
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…

751 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question