Link to home
Create AccountLog in
Avatar of -Dman100-
-Dman100-Flag for United States of America

asked on

ServerValidateEventHandler Delegate

I'm adding validation controls to a gridview at runtime when RowDataBound event fires.  I have a custom validation control method that I'm calling using the ServerValidateEventHandler Delegate.

I'm not getting any errors, but the custom validation control does not trigger.  The other validation controls that I've added at runtime work, just not the custom validation control.

Can anyone see where I made my mistake?


protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            if (GridView1.EditIndex == e.Row.RowIndex)
            {
                RequiredFieldValidator rfv1 = new RequiredFieldValidator();
                rfv1.ID = "valrDescription";
                rfv1.ControlToValidate = "txtDescription";
                rfv1.ErrorMessage = "Field cannot be empty.";
                rfv1.SetFocusOnError = true;
                rfv1.Display = ValidatorDisplay.Dynamic;
                e.Row.Cells[0].Controls.Add(rfv1);
 
                RequiredFieldValidator rfv2 = new RequiredFieldValidator();
                rfv2.ID = "valrMetric";
                rfv2.ControlToValidate = "txtMetric";
                rfv2.ErrorMessage = "Field cannot be empty.";
                rfv2.SetFocusOnError = true;
                rfv2.Display = ValidatorDisplay.Dynamic;
                e.Row.Cells[1].Controls.Add(rfv2);
 
                CustomValidator cv1 = new CustomValidator();
                cv1.ID = "valxDescription";
                cv1.ControlToValidate = "txtDescription";
                cv1.ServerValidate += new ServerValidateEventHandler(this.ValidateInputLength);
                cv1.ErrorMessage = "Field length cannot exceed 255 characters.";
                cv1.SetFocusOnError = true;
                cv1.Display = ValidatorDisplay.Dynamic;
                e.Row.Cells[0].Controls.Add(cv1);
 
            }
        }
    }
 
    protected void ValidateInputLength(object source, ServerValidateEventArgs args)
    {
        TextBox txt = (TextBox)(GridView1.FindControl("txtDescription"));
 
        if (txt.Text.Length > 255)
        {
            args.IsValid = false;
        }
        else
        {
            args.IsValid = true;
        }
    }

Open in new window

Avatar of Velio
Velio
Flag of South Africa image

hi,

this is happening because you're hooking the event too late in the page life-cycle.

1. try doing this in the OnItemCreated of the gridview
2. it doesn't seem like there's any particular reason for these validators to be created at runtime, so perhaps move them in the markup's EditItemTemplate's with an OnServerValidate="ValidateInputLength" attribute
also another possibility would be that the textbox you're validating is empty. you have to set the ValidateEmptyText property to true on the validator.
Avatar of -Dman100-

ASKER

Hi Velio,

Thanks for replying to my post.  Here is the article that I read that gave me the idea to create the validators at runtime: http://www.123aspx.com/redir.aspx?res=36965

I am creating these validators at runtime because I was unable to get the validators to work when placed in the markup's EditItemTemplate.  I kept getting errors.  Specifically, the following error:

"Invalid postback or callback argument.  Event validation is enabled using <pages enableEventValidation="true"/> in configuration or <%@ Page EnableEventValidation="true" %> in a page.  For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them.  If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation. "

I'll try placing the validtaors in the OnItemCreated event and also try setting the ValidateEmptyText property to true.
Hi Velio,

First I tried setting the ValidateEmptyText to property to true, but that didn't work.

Then I looked for the OnItemCreated event for the gridview, but I didn't see that event.  The closest event I saw was the OnRowCreated, which I tried.  When I ran the page, I got the error:

Object reference not set to an instance of an object.

I've attached the full code in a file, which might help identify where my error is.

code.txt
hi, sorry for the delay,

the only change required in the code you've provided would be the validation function (see snippet below for a working version)

i would recommend something else though - you could set the MaxLength property of the textbox to 255, then there would be no need for the custom validator.

    protected void ValidateInputLength(object source, ServerValidateEventArgs args)
    {
        args.IsValid = (args.Value.Length <= 255);
    }

Open in new window

Hi Velio...no problem at all.  Thanks for taking the time to help me.  I sincerely appreciate it.

It does make sense to just set the MaxLength property of the textbox to 255 and avoid the custom validator altogether, which is exactly what I'll do.

I still wanted to figure out how to get the custom validator to work in case I have to add some other custom validator in the future.

In your reply, do you mean the Custom Validation method should just be:

protected void ValidateInputLength(object source, ServerValidateEventArgs args)
    {
        args.IsValid = (args.Value.Length <= 255);
    }

Nothing else?  How does that validate the length of text in the textbox?  Sorry for my confusion.

I've really struggled with how to validate inputs in a gridview.  I tried several different methods and each time I've encountered problems with how I've implemented the validation.

Granted, I have the reguired fields and regular expression validations working okay, but I just can't seem to get the custom validation working.

When I tried to run the validation method shown in your post, again, it never validated.  I put in about 350 characters into the textbox, but the validator never triggered.

I'm not sure what I'm doing incorrectly.

Thanks again for your help!
Regards.
hmmm, that's strange because i'm using your exact code to create the validators, only difference is i create a datasource on the fly with some dummy data... and the custom validation works just fine.

 i don't think it'll make any difference, but am i correct in presuming 'description' is of type string?
have you tried to step through to see if the event fires/args.Value contains the the text box's Text property?

yet another alternative is to have a client-side function which performs the validation... but i won't get into that for now :)
Hi Velio,

Yes, 'description' is of type string.  It is a varchar(255) in the database.

I haven't added a breakpoint and stepped thru the code, but I'll do that now.

Here is the code I am using.  Does this all look correct?  Am I missing anything?
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            if (GridView1.EditIndex == e.Row.RowIndex)
            {
                RequiredFieldValidator rfv1 = new RequiredFieldValidator();
                rfv1.ID = "valrDescription";
                rfv1.ControlToValidate = "txtDescription";
                rfv1.ErrorMessage = "Field cannot be empty.";
                rfv1.SetFocusOnError = true;
                rfv1.Display = ValidatorDisplay.Dynamic;
                e.Row.Cells[0].Controls.Add(rfv1);
 
                RequiredFieldValidator rfv2 = new RequiredFieldValidator();
                rfv2.ID = "valrMetric";
                rfv2.ControlToValidate = "txtMetric";
                rfv2.ErrorMessage = "Field cannot be empty.";
                rfv2.SetFocusOnError = true;
                rfv2.Display = ValidatorDisplay.Dynamic;
                e.Row.Cells[1].Controls.Add(rfv2);
 
                CustomValidator cv1 = new CustomValidator();
                cv1.ID = "valxDescription";
                cv1.ControlToValidate = "txtDescription";
                cv1.ValidateEmptyText = true;
                cv1.ServerValidate += new ServerValidateEventHandler(ValidateInputLength);
                cv1.ErrorMessage = "Field length cannot exceed 255 characters.";
                cv1.SetFocusOnError = true;
                cv1.Display = ValidatorDisplay.Dynamic;
                e.Row.Cells[0].Controls.Add(cv1);
 
                RegularExpressionValidator regex1 = new RegularExpressionValidator();
                regex1.ID = "valeMetric";
                regex1.ControlToValidate = "txtMetric";
                regex1.ErrorMessage = "A numeric value is required.";
                regex1.ValidationExpression = "^[-+]?\\d+(\\.\\d+)?$";
                regex1.SetFocusOnError = true;
                regex1.Display = ValidatorDisplay.Dynamic;
                e.Row.Cells[1].Controls.Add(regex1);
            }         
        }
    }
 
    protected void ValidateInputLength(object source, ServerValidateEventArgs args)
    {
        args.IsValid = (args.Value.Length <= 255);
    }

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Velio
Velio
Flag of South Africa image

Link to home
membership
Create an account to see this answer
Signing up is free. No credit card required.
Create Account
Yes sir...that worked.  That taught me a great deal.  I am still trying to fully understand the different events and what occurs when the event is triggered.

Do you mind if I ask you one additional question?  I hope this would be a simple question.

How can I remove a character from a specific row and specific column of a gridview when it is in edit mode? I have been trying to use the RowEditing and RowDataBound events to find the row and column and then use the replace method to find the character and remove it. Everything I've tried has failed.

I've attached a screenshot of the gridview in edit mode. In the first row and second column, I'm trying to remove the '%' while the gridview is in edit mode.

I'm trying to do the exact same thing in the second row except that in the second row, I want to remove the text "seconds" from the column.

Thank you again for taking the time to help me.  Everyday I learn something new and slowly am getting a better handle coding using .net.

Best Regards!
gridview.doc
my pleasure :)

as far as removing the characters... you can do something like this:
1. create helper method to do the necessary string manipulation...
2. modify the edit  item template, so that the <%# %> portion calls your the helper method passing the result of Eval("metric") as the parameter.

here's a sample:
    protected static string StripNonNumericCharacters(string value)
    {
        string result = "";
        int decimalPointIndex = value.IndexOf('.');
        int minusIindex = value.IndexOf('-');
        for (int index = 0; index < value.Length; index++)
        {
            if ((value[index] == '-' && index == minusIindex) ||
                (value[index] == '.' && index == decimalPointIndex) ||
                (char.IsNumber(value[index])))
                result += value[index];
        }
        return result;
    }
 
....
 
<asp:TemplateField HeaderText="Metric">
                    <ItemTemplate>
                        <asp:Label ID="lblMetric" Text='<%# Eval("metric") %>' runat="server"></asp:Label>
                    </ItemTemplate>
                    <EditItemTemplate>
                        <asp:TextBox ID="txtMetric" Text='<%# StripNonNumericCharacters(Eval("metric").ToString()) %>' runat="server"></asp:TextBox>
                    </EditItemTemplate>
                    <ControlStyle Width="300px" />
                    <HeaderStyle HorizontalAlign="Left" />
                    <ItemStyle Width="300px" VerticalAlign="Top" />
                </asp:TemplateField>

Open in new window

a small bug in the StripNonNumericCharacters method - presently the first minus will be kept, regardless of its position in the string. it must only be added if minusIndex == 0.

...if you want to nitpick :)
Thanks a million Velio!!  That worked perfectly and was exactly what I needed.

Now, I'm just trying ot decipher the code in the method :)

Again, I truly appreciate your help!
some comments might be in order then :)
    protected static string StripNonNumericCharacters(string value)
    {
        //start off with an empty string
        string result = "";
        //index of the first decimal point
        int decimalPointIndex = value.IndexOf('.');
        //index of the first minus
        int minusIindex = value.IndexOf('-');
        //loop through all characters in the string that has been passed
        for (int index = 0; index < value.Length; index++)
        {       
            //if the current character is
            // * the first minus and at the beginning of the string (hence allowing negative numbers OR
            // * the first decimal points (hence allowing decimal numbers) OR
            // * is a number
            //append it to the end result
            if ((value[index] == '-' && index == minusIindex && minusIindex == 0) ||
                (value[index] == '.' && index == decimalPointIndex) ||
                (char.IsNumber(value[index])))
                result += value[index];
        }
        //you now have only the number, plus the "special characters" of the sign and decimal point, if they are present
        return result;
    }

Open in new window