Home All Groups Group Topic Archive Search About

ValidationControl evaluationfunction ASP.NET 2.0

Author
22 Jun 2006 6:17 PM
jeremy.brewster
Hello

I'm trying to work out how to call a custom evaluation function for a
Validation Control (via the "evaluationfunction" attribute) to change
the visual style of the div hosting the input control if validation
fails.  We have this working as a fallback on the server-side (if
client-side script is turned off) but want/need this working on the
client-side also.

I am working on a website which included this behaviour in .NET 1.1 but
I am having trouble getting it to work with .NET 2.0.

I've tried setting the evaluation function using:
this.validator.Attributes["evaluationfunction"] in the server-side
helper class that includes an instance of the validator but this seems
to be ignored by the browser and does not result in the client-side
function being called.  When I use:
this.validator.Page.ClientScript.RegisterExpandoAttribute("...") I
receive an error stating "System.ArgumentException: An entry with the
same key already exists."

Indeed when we use the DOM Inspector from Firefox on the page we can
see that the evaluationfunction attribute for the validator already has
the following out-of-the-box client-script defined:

function RegularExpressionValidatorEvaluateIsValid(val) {
    var value = ValidatorGetValue(val.controltovalidate);
    if (ValidatorTrim(value).length == 0) {
        return true;
    }
    var rx = new RegExp(val.validationexpression);
    var matches = rx.exec(value);
    return (matches != null && value == matches[0]);
}

So I'm thinking that what I need is the ability to change the
evaluationfunction value to my own custom code.  I'm having no luck
whatsoever with this.

Does anybody have any ideas on how to solve this.  Thanks in advance.

Jez

Author
22 Jun 2006 7:09 PM
JimOx
You could write a custom validator that implements the BaseValidator. Then if
you override AddAttributesToRender use
Page.ClientScript.RegisterExpandoAttribute(ClientID, "evaluationfunction",
"ClientSideFunctionToCall", false); and it should work.

Show quoteHide quote
"jeremy.brews***@akqa.com" wrote:

> Hello
>
> I'm trying to work out how to call a custom evaluation function for a
> Validation Control (via the "evaluationfunction" attribute) to change
> the visual style of the div hosting the input control if validation
> fails.  We have this working as a fallback on the server-side (if
> client-side script is turned off) but want/need this working on the
> client-side also.
>
> I am working on a website which included this behaviour in .NET 1.1 but
> I am having trouble getting it to work with .NET 2.0.
>
> I've tried setting the evaluation function using:
> this.validator.Attributes["evaluationfunction"] in the server-side
> helper class that includes an instance of the validator but this seems
> to be ignored by the browser and does not result in the client-side
> function being called.  When I use:
> this.validator.Page.ClientScript.RegisterExpandoAttribute("...") I
> receive an error stating "System.ArgumentException: An entry with the
> same key already exists."
>
> Indeed when we use the DOM Inspector from Firefox on the page we can
> see that the evaluationfunction attribute for the validator already has
> the following out-of-the-box client-script defined:
>
> function RegularExpressionValidatorEvaluateIsValid(val) {
>     var value = ValidatorGetValue(val.controltovalidate);
>     if (ValidatorTrim(value).length == 0) {
>         return true;
>     }
>     var rx = new RegExp(val.validationexpression);
>     var matches = rx.exec(value);
>     return (matches != null && value == matches[0]);
> }
>
> So I'm thinking that what I need is the ability to change the
> evaluationfunction value to my own custom code.  I'm having no luck
> whatsoever with this.
>
> Does anybody have any ideas on how to solve this.  Thanks in advance.
>
> Jez
>
>
Are all your drivers up to date? click for free checkup

Author
23 Jun 2006 10:20 AM
jeremy.brewster
Hi Jim

Thanks for the reply.  This is something we are already doing.  We have
subclassed each validator for which we want to create a customised
behaviour.  So we have a class with the following definition:

public class StyleChangingRequiredFieldValidator :
RequiredFieldValidator
{
    private StyleChangingHelper helper;

    /// <summary>
    /// Default constructor.
    /// </summary>
    public StyleChangingRequiredFieldValidator()
    {
        this.helper = new StyleChangingHelper(this);
    }

    /// <summary>
    /// The control whose style should be changed when validation results
in an invalid state.
    /// </summary>
    public string ControlToChange
    {
        get
        {
            return this.helper.ControlToChange;
        }
        set
        {
            this.helper.ControlToChange = value;
        }
    }

    /// <summary>
    /// The CSS class to use when changing the style of the targeted
control.
    /// </summary>
    public string ChangeCssClass
    {
        get
        {
            return this.helper.ChangeCssClass;
        }
        set
        {
            this.helper.ChangeCssClass = value;
        }
    }

    /// <summary>
    /// Raises the Init event.
    /// </summary>
    /// <param name="e">An EventArgs object that contains the event
data.</param>
    protected override void OnInit(System.EventArgs e)
    {
        base.OnInit(e);
        this.helper.OnInit(e);
    }

    /// <summary>
    /// Determines whether the value in the input control is valid.
    /// </summary>
    /// <returns><c>true</c> if the value in the input control is valid;
otherwise, <c>false</c>.</returns>
    protected override bool EvaluateIsValid()
    {
        bool isValid = base.EvaluateIsValid();
        return this.helper.EvaluateIsValid(isValid);
    }

    /// <summary>
    /// Raises the PreRender event.
    /// </summary>
    /// <param name="e">An EventArgs object that contains the event
data.</param>
    protected override void OnPreRender(System.EventArgs e)
    {
        this.helper.OnPreRender(e);
        base.OnPreRender(e);
    }

    /// <summary>
    /// Adds HTML attributes and styles that need to be rendered to the
specified System.Web.UI.HtmlTextWriter.
    /// </summary>
    /// <param name="writer">A System.Web.UI.HtmlTextWriter that
represents the output stream to render HTML content on the
client.</param>
    protected override void AddAttributesToRender(HtmlTextWriter writer)
    {
        base.AddAttributesToRender(writer);
        this.helper.AddAttributesToRender(writer, this.RenderUplevel);
    }
}

We have created a StyleChangingHelper class, an instance of which is
instantiated by each Validator derived subclass, and objects based on
this class handle the writing of the attributes.

/// <summary>
/// Provides functionality for style changing validation controls.
/// </summary>
public class StyleChangingHelper
{
    private BaseValidator validator;
    private string controlToChange;
    private string changeCssClass;
    private object foundControl;
    private string originalCssClass;
    private const string evaluationFunctionSuffix = "_Verify";

    /// <summary>
    /// Constructor which initialises the helper with a validator
instance.
    /// </summary>
    /// <param name="validator">The validator that this helper will be
helping.</param>
    public StyleChangingHelper(BaseValidator validator)
    {
        this.validator = validator;
    }

    /// <summary>
    /// The control whose style should be changed when validation results
in an invalid state.
    /// </summary>
    public string ControlToChange
    {
        get
        {
            return this.controlToChange;
        }
        set
        {
            this.controlToChange = value;
        }
    }

    /// <summary>
    /// The CSS class to use when changing the style of the targeted
control.
    /// </summary>
    public string ChangeCssClass
    {
        get
        {
            return this.changeCssClass;
        }
        set
        {
            this.changeCssClass = value;
        }
    }

    /// <summary>
    /// Should be called by the base validator upon raising the Init
event.
    /// </summary>
    /// <param name="e">An EventArgs object that contains the event
data.</param>
    public void OnInit(System.EventArgs e)
    {
                               string controlID = DeriveId('$');

        this.foundControl = this.validator.Page.FindControl(controlID);
        if (this.foundControl != null)
        {
            if (this.foundControl is WebControl)
            {
                WebControl foundWebControl = (WebControl) this.foundControl;
                this.originalCssClass = foundWebControl.CssClass;
            }
            else if (foundControl is HtmlControl)
            {
                HtmlControl foundHtmlControl = (HtmlControl) this.foundControl;
                this.originalCssClass = foundHtmlControl.Attributes["class"];
            }
        }
    }

    /// <summary>
    /// Determines whether the value in the input control is valid.
    /// </summary>
    /// <param name="isValid">Indicates whether the calling validator
considers the input control valid.</param>
    public bool EvaluateIsValid(bool isValid)
    {
        if (!isValid)
        {
            if (this.foundControl != null)
            {
                if (this.foundControl is WebControl)
                {
                    WebControl foundWebControl = (WebControl) this.foundControl;

foundWebControl.CssClass = this.changeCssClass;
                }
                else if (foundControl is HtmlControl)
                {
                    HtmlControl foundHtmlControl = (HtmlControl) this.foundControl;
                    foundHtmlControl.Attributes.Add("class", this.changeCssClass);
                }
            }
        }
        return isValid;
    }

    /// <summary>
    /// Should be called by the base validator upon raising the PreRender
event.
    /// </summary>
    /// <param name="e">An EventArgs object that contains the event
data.</param>
    public void OnPreRender(System.EventArgs e)
    {
        if (this.validator.EnableClientScript)
        {
//            this.validator.Attributes["evaluationfunction"] =
this.validator.GetType().Name + evaluationFunctionSuffix;



this.validator.Page.ClientScript.RegisterExpandoAttribute(validator.ClientID,
"evaluationfunction", this.validator.GetType().Name +
evaluationFunctionSuffix);
        }
    }

    /// <summary>
    /// Adds HTML attributes and styles that need to be rendered to the
specified System.Web.UI.HtmlTextWriter.
    /// </summary>
    /// <param name="writer">A System.Web.UI.HtmlTextWriter that
represents the output stream to render HTML content on the
client.</param>
    /// <param name="renderUpLevel">Indicates whether the client's browser
supports uplevel rendering.</param>
    public void AddAttributesToRender(HtmlTextWriter writer, bool
renderUpLevel)
    {
        if (renderUpLevel)
        {
            string renderedControlID;
                                                renderedControlID =
DeriveId('_');

                        writer.AddAttribute("controltochange",
renderedControlID);
            writer.AddAttribute("changecssclass", ChangeCssClass);
            writer.AddAttribute("originalcssclass", this.originalCssClass);
        }
    }
}

When I compile and run this code, we receive a
"System.ArgumentException: An entry with the same key already exists."
highlighting the AddAttributesToRender method in the
StyleChangingRequiredFieldValidator class.

If I don't use the Page.ClientScript.RegisterExpandoAttribute method to
write the evaluationfunction attribute (instead using:
validator.Attributes["evaluationfunction"] = ...) then the value
written is effectively ignored by the web page (although written to the
page html as observed in notepad).  When I say that it is ignored by
the web page, I know this from running the Firefox DOM Inspector which
states that the ASP.NET out-of-the-box required field validator
function is being used.

function RequiredFieldValidatorEvaluateIsValid(val) {
    return (ValidatorTrim(ValidatorGetValue(val.controltovalidate)) !=
ValidatorTrim(val.initialvalue));
}

So I'm again stuck with not being able to replace the out-of-the-box
javascript evaluationfunction value with my own custom implementation
in which I want to dynamically change the style of the div elements
hosting the input control should validation fail.

Does anybody have any ideas?

Thanks

Jez


JimOx wrote:
Show quoteHide quote
> You could write a custom validator that implements the BaseValidator. Then if
> you override AddAttributesToRender use
> Page.ClientScript.RegisterExpandoAttribute(ClientID, "evaluationfunction",
> "ClientSideFunctionToCall", false); and it should work.
>
> "jeremy.brews***@akqa.com" wrote:
>
> > Hello
> >
> > I'm trying to work out how to call a custom evaluation function for a
> > Validation Control (via the "evaluationfunction" attribute) to change
> > the visual style of the div hosting the input control if validation
> > fails.  We have this working as a fallback on the server-side (if
> > client-side script is turned off) but want/need this working on the
> > client-side also.
> >
> > I am working on a website which included this behaviour in .NET 1.1 but
> > I am having trouble getting it to work with .NET 2.0.
> >
> > I've tried setting the evaluation function using:
> > this.validator.Attributes["evaluationfunction"] in the server-side
> > helper class that includes an instance of the validator but this seems
> > to be ignored by the browser and does not result in the client-side
> > function being called.  When I use:
> > this.validator.Page.ClientScript.RegisterExpandoAttribute("...") I
> > receive an error stating "System.ArgumentException: An entry with the
> > same key already exists."
> >
> > Indeed when we use the DOM Inspector from Firefox on the page we can
> > see that the evaluationfunction attribute for the validator already has
> > the following out-of-the-box client-script defined:
> >
> > function RegularExpressionValidatorEvaluateIsValid(val) {
> >     var value = ValidatorGetValue(val.controltovalidate);
> >     if (ValidatorTrim(value).length == 0) {
> >         return true;
> >     }
> >     var rx = new RegExp(val.validationexpression);
> >     var matches = rx.exec(value);
> >     return (matches != null && value == matches[0]);
> > }
> >
> > So I'm thinking that what I need is the ability to change the
> > evaluationfunction value to my own custom code.  I'm having no luck
> > whatsoever with this.
> >
> > Does anybody have any ideas on how to solve this.  Thanks in advance.
> >
> > Jez
> >
> >
Author
23 Jun 2006 11:20 AM
Alessandro Zifiglio
hi Jeremy, in your override of AddAttributesToRender, do not call
base.AddAttributesToRender. Instead what you need to do is override this
method as you are currently doing and add apply your customized attributes
to it, which is probably being done via the method call to your helper
class.

Regards,
Alessandro Zifiglio
<jeremy.brews***@akqa.com> ha scritto nel messaggio
Show quoteHide quote
news:1151058013.109033.231650@m73g2000cwd.googlegroups.com...
> Hi Jim
>
> Thanks for the reply.  This is something we are already doing.  We have
> subclassed each validator for which we want to create a customised
> behaviour.  So we have a class with the following definition:
>
> public class StyleChangingRequiredFieldValidator :
> RequiredFieldValidator
> {
> private StyleChangingHelper helper;
>
> /// <summary>
> /// Default constructor.
> /// </summary>
> public StyleChangingRequiredFieldValidator()
> {
> this.helper = new StyleChangingHelper(this);
> }
>
> /// <summary>
> /// The control whose style should be changed when validation results
> in an invalid state.
> /// </summary>
> public string ControlToChange
> {
> get
> {
> return this.helper.ControlToChange;
> }
> set
> {
> this.helper.ControlToChange = value;
> }
> }
>
> /// <summary>
> /// The CSS class to use when changing the style of the targeted
> control.
> /// </summary>
> public string ChangeCssClass
> {
> get
> {
> return this.helper.ChangeCssClass;
> }
> set
> {
> this.helper.ChangeCssClass = value;
> }
> }
>
> /// <summary>
> /// Raises the Init event.
> /// </summary>
> /// <param name="e">An EventArgs object that contains the event
> data.</param>
> protected override void OnInit(System.EventArgs e)
> {
> base.OnInit(e);
> this.helper.OnInit(e);
> }
>
> /// <summary>
> /// Determines whether the value in the input control is valid.
> /// </summary>
> /// <returns><c>true</c> if the value in the input control is valid;
> otherwise, <c>false</c>.</returns>
> protected override bool EvaluateIsValid()
> {
> bool isValid = base.EvaluateIsValid();
> return this.helper.EvaluateIsValid(isValid);
> }
>
> /// <summary>
> /// Raises the PreRender event.
> /// </summary>
> /// <param name="e">An EventArgs object that contains the event
> data.</param>
> protected override void OnPreRender(System.EventArgs e)
> {
> this.helper.OnPreRender(e);
> base.OnPreRender(e);
> }
>
> /// <summary>
> /// Adds HTML attributes and styles that need to be rendered to the
> specified System.Web.UI.HtmlTextWriter.
> /// </summary>
> /// <param name="writer">A System.Web.UI.HtmlTextWriter that
> represents the output stream to render HTML content on the
> client.</param>
> protected override void AddAttributesToRender(HtmlTextWriter writer)
> {
> base.AddAttributesToRender(writer);
> this.helper.AddAttributesToRender(writer, this.RenderUplevel);
> }
> }
>
> We have created a StyleChangingHelper class, an instance of which is
> instantiated by each Validator derived subclass, and objects based on
> this class handle the writing of the attributes.
>
> /// <summary>
> /// Provides functionality for style changing validation controls.
> /// </summary>
> public class StyleChangingHelper
> {
> private BaseValidator validator;
> private string controlToChange;
> private string changeCssClass;
> private object foundControl;
> private string originalCssClass;
> private const string evaluationFunctionSuffix = "_Verify";
>
> /// <summary>
> /// Constructor which initialises the helper with a validator
> instance.
> /// </summary>
> /// <param name="validator">The validator that this helper will be
> helping.</param>
> public StyleChangingHelper(BaseValidator validator)
> {
> this.validator = validator;
> }
>
> /// <summary>
> /// The control whose style should be changed when validation results
> in an invalid state.
> /// </summary>
> public string ControlToChange
> {
> get
> {
> return this.controlToChange;
> }
> set
> {
> this.controlToChange = value;
> }
> }
>
> /// <summary>
> /// The CSS class to use when changing the style of the targeted
> control.
> /// </summary>
> public string ChangeCssClass
> {
> get
> {
> return this.changeCssClass;
> }
> set
> {
> this.changeCssClass = value;
> }
> }
>
> /// <summary>
> /// Should be called by the base validator upon raising the Init
> event.
> /// </summary>
> /// <param name="e">An EventArgs object that contains the event
> data.</param>
> public void OnInit(System.EventArgs e)
> {
>                               string controlID = DeriveId('$');
>
> this.foundControl = this.validator.Page.FindControl(controlID);
> if (this.foundControl != null)
> {
> if (this.foundControl is WebControl)
> {
> WebControl foundWebControl = (WebControl) this.foundControl;
> this.originalCssClass = foundWebControl.CssClass;
> }
> else if (foundControl is HtmlControl)
> {
> HtmlControl foundHtmlControl = (HtmlControl) this.foundControl;
> this.originalCssClass = foundHtmlControl.Attributes["class"];
> }
> }
> }
>
> /// <summary>
> /// Determines whether the value in the input control is valid.
> /// </summary>
> /// <param name="isValid">Indicates whether the calling validator
> considers the input control valid.</param>
> public bool EvaluateIsValid(bool isValid)
> {
> if (!isValid)
> {
> if (this.foundControl != null)
> {
> if (this.foundControl is WebControl)
> {
> WebControl foundWebControl = (WebControl) this.foundControl;
>
> foundWebControl.CssClass = this.changeCssClass;
> }
> else if (foundControl is HtmlControl)
> {
> HtmlControl foundHtmlControl = (HtmlControl) this.foundControl;
> foundHtmlControl.Attributes.Add("class", this.changeCssClass);
> }
> }
> }
> return isValid;
> }
>
> /// <summary>
> /// Should be called by the base validator upon raising the PreRender
> event.
> /// </summary>
> /// <param name="e">An EventArgs object that contains the event
> data.</param>
> public void OnPreRender(System.EventArgs e)
> {
> if (this.validator.EnableClientScript)
> {
> // this.validator.Attributes["evaluationfunction"] =
> this.validator.GetType().Name + evaluationFunctionSuffix;
>
>
>
> this.validator.Page.ClientScript.RegisterExpandoAttribute(validator.ClientID,
> "evaluationfunction", this.validator.GetType().Name +
> evaluationFunctionSuffix);
> }
> }
>
> /// <summary>
> /// Adds HTML attributes and styles that need to be rendered to the
> specified System.Web.UI.HtmlTextWriter.
> /// </summary>
> /// <param name="writer">A System.Web.UI.HtmlTextWriter that
> represents the output stream to render HTML content on the
> client.</param>
> /// <param name="renderUpLevel">Indicates whether the client's browser
> supports uplevel rendering.</param>
> public void AddAttributesToRender(HtmlTextWriter writer, bool
> renderUpLevel)
> {
> if (renderUpLevel)
> {
> string renderedControlID;
>                                                renderedControlID =
> DeriveId('_');
>
>                 writer.AddAttribute("controltochange",
> renderedControlID);
> writer.AddAttribute("changecssclass", ChangeCssClass);
> writer.AddAttribute("originalcssclass", this.originalCssClass);
> }
> }
> }
>
> When I compile and run this code, we receive a
> "System.ArgumentException: An entry with the same key already exists."
> highlighting the AddAttributesToRender method in the
> StyleChangingRequiredFieldValidator class.
>
> If I don't use the Page.ClientScript.RegisterExpandoAttribute method to
> write the evaluationfunction attribute (instead using:
> validator.Attributes["evaluationfunction"] = ...) then the value
> written is effectively ignored by the web page (although written to the
> page html as observed in notepad).  When I say that it is ignored by
> the web page, I know this from running the Firefox DOM Inspector which
> states that the ASP.NET out-of-the-box required field validator
> function is being used.
>
> function RequiredFieldValidatorEvaluateIsValid(val) {
>    return (ValidatorTrim(ValidatorGetValue(val.controltovalidate)) !=
> ValidatorTrim(val.initialvalue));
> }
>
> So I'm again stuck with not being able to replace the out-of-the-box
> javascript evaluationfunction value with my own custom implementation
> in which I want to dynamically change the style of the div elements
> hosting the input control should validation fail.
>
> Does anybody have any ideas?
>
> Thanks
>
> Jez
>
>
> JimOx wrote:
>> You could write a custom validator that implements the BaseValidator.
>> Then if
>> you override AddAttributesToRender use
>> Page.ClientScript.RegisterExpandoAttribute(ClientID,
>> "evaluationfunction",
>> "ClientSideFunctionToCall", false); and it should work.
>>
>> "jeremy.brews***@akqa.com" wrote:
>>
>> > Hello
>> >
>> > I'm trying to work out how to call a custom evaluation function for a
>> > Validation Control (via the "evaluationfunction" attribute) to change
>> > the visual style of the div hosting the input control if validation
>> > fails.  We have this working as a fallback on the server-side (if
>> > client-side script is turned off) but want/need this working on the
>> > client-side also.
>> >
>> > I am working on a website which included this behaviour in .NET 1.1 but
>> > I am having trouble getting it to work with .NET 2.0.
>> >
>> > I've tried setting the evaluation function using:
>> > this.validator.Attributes["evaluationfunction"] in the server-side
>> > helper class that includes an instance of the validator but this seems
>> > to be ignored by the browser and does not result in the client-side
>> > function being called.  When I use:
>> > this.validator.Page.ClientScript.RegisterExpandoAttribute("...") I
>> > receive an error stating "System.ArgumentException: An entry with the
>> > same key already exists."
>> >
>> > Indeed when we use the DOM Inspector from Firefox on the page we can
>> > see that the evaluationfunction attribute for the validator already has
>> > the following out-of-the-box client-script defined:
>> >
>> > function RegularExpressionValidatorEvaluateIsValid(val) {
>> >     var value = ValidatorGetValue(val.controltovalidate);
>> >     if (ValidatorTrim(value).length == 0) {
>> >         return true;
>> >     }
>> >     var rx = new RegExp(val.validationexpression);
>> >     var matches = rx.exec(value);
>> >     return (matches != null && value == matches[0]);
>> > }
>> >
>> > So I'm thinking that what I need is the ability to change the
>> > evaluationfunction value to my own custom code.  I'm having no luck
>> > whatsoever with this.
>> >
>> > Does anybody have any ideas on how to solve this.  Thanks in advance.
>> >
>> > Jez
>> >
>> >
>
Author
23 Jun 2006 1:33 PM
jeremy.brewster
Hi Alessando

If I don't call the validator base.AddAttributesToRender then no aspect
of the validator gets written to the page.

As you say, I am overriding the AddAttributesToRender method in my
custom validators and they do indeed call the StyleChangingHelper
instance variable's method of the same name.

MSDN states "Notes to Inheritors When overriding the
AddAttributesToRender method, be sure to call the corresponding method
in the base class. Otherwise, the attributes contained in the base
class will not be rendered."

Or are you suggesting that my override that does not call the base
implementation needs to do more than it is doing at the minute?

The StyleChangingRequiredFieldValidator has the following OnPreRender
and AddAttributesToRender methods:

/// <summary>
/// Raises the PreRender event.
/// </summary>
/// <param name="e">An EventArgs object that contains the event
data.</param>
protected override void OnPreRender(System.EventArgs e)
{
    this.helper.OnPreRender(e);
    base.OnPreRender(e);
}

/// <summary>
/// Adds HTML attributes and styles that need to be rendered to the
specified System.Web.UI.HtmlTextWriter.
/// </summary>
/// <param name="writer">A System.Web.UI.HtmlTextWriter that represents
the output stream to render HTML content on the client.</param>
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
    base.AddAttributesToRender(writer);
    this.helper.AddAttributesToRender(writer, this.RenderUplevel);
}

The StyleChangingHelper has the following custom methods of the same
names:

/// <summary>
/// Should be called by the base validator upon raising the PreRender
event.
/// </summary>
/// <param name="e">An EventArgs object that contains the event
data.</param>
public void OnPreRender(System.EventArgs e)
{
    if (this.validator.EnableClientScript)
    {
//        this.validator.Attributes["evaluationfunction"] =
this.validator.GetType().Name + evaluationFunctionSuffix;
this.validator.Page.ClientScript.RegisterExpandoAttribute(validator.ClientID,
"evaluationfunction", this.validator.GetType().Name +
evaluationFunctionSuffix);
    }
}

/// <summary>
/// Adds HTML attributes and styles that need to be rendered to the
specified System.Web.UI.HtmlTextWriter.
/// </summary>
/// <param name="writer">A System.Web.UI.HtmlTextWriter that represents
the output stream to render HTML content on the client.</param>
/// <param name="renderUpLevel">Indicates whether the client's browser
supports uplevel rendering.</param>
public void AddAttributesToRender(HtmlTextWriter writer, bool
renderUpLevel)
{
    if (renderUpLevel)
    {
        string renderedControlID;
renderedControlID = DeriveId('_');

        writer.AddAttribute("controltochange", renderedControlID);
        writer.AddAttribute("changecssclass", ChangeCssClass);
        writer.AddAttribute("originalcssclass", this.originalCssClass);
    }
}


Alessandro Zifiglio wrote:
Show quoteHide quote
> hi Jeremy, in your override of AddAttributesToRender, do not call
> base.AddAttributesToRender. Instead what you need to do is override this
> method as you are currently doing and add apply your customized attributes
> to it, which is probably being done via the method call to your helper
> class.
>
> Regards,
> Alessandro Zifiglio
> <jeremy.brews***@akqa.com> ha scritto nel messaggio
> news:1151058013.109033.231650@m73g2000cwd.googlegroups.com...
> > Hi Jim
> >
> > Thanks for the reply.  This is something we are already doing.  We have
> > subclassed each validator for which we want to create a customised
> > behaviour.  So we have a class with the following definition:
> >
> > public class StyleChangingRequiredFieldValidator :
> > RequiredFieldValidator
> > {
> > private StyleChangingHelper helper;
> >
> > /// <summary>
> > /// Default constructor.
> > /// </summary>
> > public StyleChangingRequiredFieldValidator()
> > {
> > this.helper = new StyleChangingHelper(this);
> > }
> >
> > /// <summary>
> > /// The control whose style should be changed when validation results
> > in an invalid state.
> > /// </summary>
> > public string ControlToChange
> > {
> > get
> > {
> > return this.helper.ControlToChange;
> > }
> > set
> > {
> > this.helper.ControlToChange = value;
> > }
> > }
> >
> > /// <summary>
> > /// The CSS class to use when changing the style of the targeted
> > control.
> > /// </summary>
> > public string ChangeCssClass
> > {
> > get
> > {
> > return this.helper.ChangeCssClass;
> > }
> > set
> > {
> > this.helper.ChangeCssClass = value;
> > }
> > }
> >
> > /// <summary>
> > /// Raises the Init event.
> > /// </summary>
> > /// <param name="e">An EventArgs object that contains the event
> > data.</param>
> > protected override void OnInit(System.EventArgs e)
> > {
> > base.OnInit(e);
> > this.helper.OnInit(e);
> > }
> >
> > /// <summary>
> > /// Determines whether the value in the input control is valid.
> > /// </summary>
> > /// <returns><c>true</c> if the value in the input control is valid;
> > otherwise, <c>false</c>.</returns>
> > protected override bool EvaluateIsValid()
> > {
> > bool isValid = base.EvaluateIsValid();
> > return this.helper.EvaluateIsValid(isValid);
> > }
> >
> > /// <summary>
> > /// Raises the PreRender event.
> > /// </summary>
> > /// <param name="e">An EventArgs object that contains the event
> > data.</param>
> > protected override void OnPreRender(System.EventArgs e)
> > {
> > this.helper.OnPreRender(e);
> > base.OnPreRender(e);
> > }
> >
> > /// <summary>
> > /// Adds HTML attributes and styles that need to be rendered to the
> > specified System.Web.UI.HtmlTextWriter.
> > /// </summary>
> > /// <param name="writer">A System.Web.UI.HtmlTextWriter that
> > represents the output stream to render HTML content on the
> > client.</param>
> > protected override void AddAttributesToRender(HtmlTextWriter writer)
> > {
> > base.AddAttributesToRender(writer);
> > this.helper.AddAttributesToRender(writer, this.RenderUplevel);
> > }
> > }
> >
> > We have created a StyleChangingHelper class, an instance of which is
> > instantiated by each Validator derived subclass, and objects based on
> > this class handle the writing of the attributes.
> >
> > /// <summary>
> > /// Provides functionality for style changing validation controls.
> > /// </summary>
> > public class StyleChangingHelper
> > {
> > private BaseValidator validator;
> > private string controlToChange;
> > private string changeCssClass;
> > private object foundControl;
> > private string originalCssClass;
> > private const string evaluationFunctionSuffix = "_Verify";
> >
> > /// <summary>
> > /// Constructor which initialises the helper with a validator
> > instance.
> > /// </summary>
> > /// <param name="validator">The validator that this helper will be
> > helping.</param>
> > public StyleChangingHelper(BaseValidator validator)
> > {
> > this.validator = validator;
> > }
> >
> > /// <summary>
> > /// The control whose style should be changed when validation results
> > in an invalid state.
> > /// </summary>
> > public string ControlToChange
> > {
> > get
> > {
> > return this.controlToChange;
> > }
> > set
> > {
> > this.controlToChange = value;
> > }
> > }
> >
> > /// <summary>
> > /// The CSS class to use when changing the style of the targeted
> > control.
> > /// </summary>
> > public string ChangeCssClass
> > {
> > get
> > {
> > return this.changeCssClass;
> > }
> > set
> > {
> > this.changeCssClass = value;
> > }
> > }
> >
> > /// <summary>
> > /// Should be called by the base validator upon raising the Init
> > event.
> > /// </summary>
> > /// <param name="e">An EventArgs object that contains the event
> > data.</param>
> > public void OnInit(System.EventArgs e)
> > {
> >                               string controlID = DeriveId('$');
> >
> > this.foundControl = this.validator.Page.FindControl(controlID);
> > if (this.foundControl != null)
> > {
> > if (this.foundControl is WebControl)
> > {
> > WebControl foundWebControl = (WebControl) this.foundControl;
> > this.originalCssClass = foundWebControl.CssClass;
> > }
> > else if (foundControl is HtmlControl)
> > {
> > HtmlControl foundHtmlControl = (HtmlControl) this.foundControl;
> > this.originalCssClass = foundHtmlControl.Attributes["class"];
> > }
> > }
> > }
> >
> > /// <summary>
> > /// Determines whether the value in the input control is valid.
> > /// </summary>
> > /// <param name="isValid">Indicates whether the calling validator
> > considers the input control valid.</param>
> > public bool EvaluateIsValid(bool isValid)
> > {
> > if (!isValid)
> > {
> > if (this.foundControl != null)
> > {
> > if (this.foundControl is WebControl)
> > {
> > WebControl foundWebControl = (WebControl) this.foundControl;
> >
> > foundWebControl.CssClass = this.changeCssClass;
> > }
> > else if (foundControl is HtmlControl)
> > {
> > HtmlControl foundHtmlControl = (HtmlControl) this.foundControl;
> > foundHtmlControl.Attributes.Add("class", this.changeCssClass);
> > }
> > }
> > }
> > return isValid;
> > }
> >
> > /// <summary>
> > /// Should be called by the base validator upon raising the PreRender
> > event.
> > /// </summary>
> > /// <param name="e">An EventArgs object that contains the event
> > data.</param>
> > public void OnPreRender(System.EventArgs e)
> > {
> > if (this.validator.EnableClientScript)
> > {
> > // this.validator.Attributes["evaluationfunction"] =
> > this.validator.GetType().Name + evaluationFunctionSuffix;
> >
> >
> >
> > this.validator.Page.ClientScript.RegisterExpandoAttribute(validator.ClientID,
> > "evaluationfunction", this.validator.GetType().Name +
> > evaluationFunctionSuffix);
> > }
> > }
> >
> > /// <summary>
> > /// Adds HTML attributes and styles that need to be rendered to the
> > specified System.Web.UI.HtmlTextWriter.
> > /// </summary>
> > /// <param name="writer">A System.Web.UI.HtmlTextWriter that
> > represents the output stream to render HTML content on the
> > client.</param>
> > /// <param name="renderUpLevel">Indicates whether the client's browser
> > supports uplevel rendering.</param>
> > public void AddAttributesToRender(HtmlTextWriter writer, bool
> > renderUpLevel)
> > {
> > if (renderUpLevel)
> > {
> > string renderedControlID;
> >                                                renderedControlID =
> > DeriveId('_');
> >
> >                 writer.AddAttribute("controltochange",
> > renderedControlID);
> > writer.AddAttribute("changecssclass", ChangeCssClass);
> > writer.AddAttribute("originalcssclass", this.originalCssClass);
> > }
> > }
> > }
> >
> > When I compile and run this code, we receive a
> > "System.ArgumentException: An entry with the same key already exists."
> > highlighting the AddAttributesToRender method in the
> > StyleChangingRequiredFieldValidator class.
> >
> > If I don't use the Page.ClientScript.RegisterExpandoAttribute method to
> > write the evaluationfunction attribute (instead using:
> > validator.Attributes["evaluationfunction"] = ...) then the value
> > written is effectively ignored by the web page (although written to the
> > page html as observed in notepad).  When I say that it is ignored by
> > the web page, I know this from running the Firefox DOM Inspector which
> > states that the ASP.NET out-of-the-box required field validator
> > function is being used.
> >
> > function RequiredFieldValidatorEvaluateIsValid(val) {
> >    return (ValidatorTrim(ValidatorGetValue(val.controltovalidate)) !=
> > ValidatorTrim(val.initialvalue));
> > }
> >
> > So I'm again stuck with not being able to replace the out-of-the-box
> > javascript evaluationfunction value with my own custom implementation
> > in which I want to dynamically change the style of the div elements
> > hosting the input control should validation fail.
> >
> > Does anybody have any ideas?
> >
> > Thanks
> >
> > Jez
> >
> >
> > JimOx wrote:
> >> You could write a custom validator that implements the BaseValidator.
> >> Then if
> >> you override AddAttributesToRender use
> >> Page.ClientScript.RegisterExpandoAttribute(ClientID,
> >> "evaluationfunction",
> >> "ClientSideFunctionToCall", false); and it should work.
> >>
> >> "jeremy.brews***@akqa.com" wrote:
> >>
> >> > Hello
> >> >
> >> > I'm trying to work out how to call a custom evaluation function for a
> >> > Validation Control (via the "evaluationfunction" attribute) to change
> >> > the visual style of the div hosting the input control if validation
> >> > fails.  We have this working as a fallback on the server-side (if
> >> > client-side script is turned off) but want/need this working on the
> >> > client-side also.
> >> >
> >> > I am working on a website which included this behaviour in .NET 1.1 but
> >> > I am having trouble getting it to work with .NET 2.0.
> >> >
> >> > I've tried setting the evaluation function using:
> >> > this.validator.Attributes["evaluationfunction"] in the server-side
> >> > helper class that includes an instance of the validator but this seems
> >> > to be ignored by the browser and does not result in the client-side
> >> > function being called.  When I use:
> >> > this.validator.Page.ClientScript.RegisterExpandoAttribute("...") I
> >> > receive an error stating "System.ArgumentException: An entry with the
> >> > same key already exists."
> >> >
> >> > Indeed when we use the DOM Inspector from Firefox on the page we can
> >> > see that the evaluationfunction attribute for the validator already has
> >> > the following out-of-the-box client-script defined:
> >> >
> >> > function RegularExpressionValidatorEvaluateIsValid(val) {
> >> >     var value = ValidatorGetValue(val.controltovalidate);
> >> >     if (ValidatorTrim(value).length == 0) {
> >> >         return true;
> >> >     }
> >> >     var rx = new RegExp(val.validationexpression);
> >> >     var matches = rx.exec(value);
> >> >     return (matches != null && value == matches[0]);
> >> > }
> >> >
> >> > So I'm thinking that what I need is the ability to change the
> >> > evaluationfunction value to my own custom code.  I'm having no luck
> >> > whatsoever with this.
> >> >
> >> > Does anybody have any ideas on how to solve this.  Thanks in advance.
> >> >
> >> > Jez
> >> >
> >> >
> >
Author
23 Jun 2006 2:48 PM
JimOx
Jeremy,

I believe that to do this you can go one of two ways.  Either don't call the
base.AddAttributesToRender in your overriding method.  This will require you
to have to manually register all of the attributes that the base class would
have registered that you need.  The other option is to inherit from
BaseValidator instead of RequiredFieldValidator.  This is because
BaseValidator does not register the
"evaluationfunction" attribute but RequiredFieldValidator does and as far as
I know once an ExpandoAttribute is registered there is no way to change it's
value or remove the original.

As a side note you will need to use
Page.ClientScript.RegisterExpandoAttribute to write the attribute instead of
writer.AddAttribute.  This is because if you use writer.AddAttribute it will
work in IE but not FireFox.  However
Page.ClientScript.RegisterExpandoAttribute will work in both.

Show quoteHide quote
"jeremy.brews***@akqa.com" wrote:

> Hi Alessando
>
> If I don't call the validator base.AddAttributesToRender then no aspect
> of the validator gets written to the page.
>
> As you say, I am overriding the AddAttributesToRender method in my
> custom validators and they do indeed call the StyleChangingHelper
> instance variable's method of the same name.
>
> MSDN states "Notes to Inheritors When overriding the
> AddAttributesToRender method, be sure to call the corresponding method
> in the base class. Otherwise, the attributes contained in the base
> class will not be rendered."
>
> Or are you suggesting that my override that does not call the base
> implementation needs to do more than it is doing at the minute?
>
> The StyleChangingRequiredFieldValidator has the following OnPreRender
> and AddAttributesToRender methods:
>
> /// <summary>
> /// Raises the PreRender event.
> /// </summary>
> /// <param name="e">An EventArgs object that contains the event
> data.</param>
> protected override void OnPreRender(System.EventArgs e)
> {
>     this.helper.OnPreRender(e);
>     base.OnPreRender(e);
> }
>
> /// <summary>
> /// Adds HTML attributes and styles that need to be rendered to the
> specified System.Web.UI.HtmlTextWriter.
> /// </summary>
> /// <param name="writer">A System.Web.UI.HtmlTextWriter that represents
> the output stream to render HTML content on the client.</param>
> protected override void AddAttributesToRender(HtmlTextWriter writer)
> {
>     base.AddAttributesToRender(writer);
>     this.helper.AddAttributesToRender(writer, this.RenderUplevel);
> }
>
> The StyleChangingHelper has the following custom methods of the same
> names:
>
> /// <summary>
> /// Should be called by the base validator upon raising the PreRender
> event.
> /// </summary>
> /// <param name="e">An EventArgs object that contains the event
> data.</param>
> public void OnPreRender(System.EventArgs e)
> {
>     if (this.validator.EnableClientScript)
>     {
> //        this.validator.Attributes["evaluationfunction"] =
> this.validator.GetType().Name + evaluationFunctionSuffix;
> this.validator.Page.ClientScript.RegisterExpandoAttribute(validator.ClientID,
> "evaluationfunction", this.validator.GetType().Name +
> evaluationFunctionSuffix);
>     }
> }
>
> /// <summary>
> /// Adds HTML attributes and styles that need to be rendered to the
> specified System.Web.UI.HtmlTextWriter.
> /// </summary>
> /// <param name="writer">A System.Web.UI.HtmlTextWriter that represents
> the output stream to render HTML content on the client.</param>
> /// <param name="renderUpLevel">Indicates whether the client's browser
> supports uplevel rendering.</param>
> public void AddAttributesToRender(HtmlTextWriter writer, bool
> renderUpLevel)
> {
>     if (renderUpLevel)
>     {
>         string renderedControlID;
> renderedControlID = DeriveId('_');
>
>         writer.AddAttribute("controltochange", renderedControlID);
>         writer.AddAttribute("changecssclass", ChangeCssClass);
>         writer.AddAttribute("originalcssclass", this.originalCssClass);
>     }
> }
>
>
> Alessandro Zifiglio wrote:
> > hi Jeremy, in your override of AddAttributesToRender, do not call
> > base.AddAttributesToRender. Instead what you need to do is override this
> > method as you are currently doing and add apply your customized attributes
> > to it, which is probably being done via the method call to your helper
> > class.
> >
> > Regards,
> > Alessandro Zifiglio
> > <jeremy.brews***@akqa.com> ha scritto nel messaggio
> > news:1151058013.109033.231650@m73g2000cwd.googlegroups.com...
> > > Hi Jim
> > >
> > > Thanks for the reply.  This is something we are already doing.  We have
> > > subclassed each validator for which we want to create a customised
> > > behaviour.  So we have a class with the following definition:
> > >
> > > public class StyleChangingRequiredFieldValidator :
> > > RequiredFieldValidator
> > > {
> > > private StyleChangingHelper helper;
> > >
> > > /// <summary>
> > > /// Default constructor.
> > > /// </summary>
> > > public StyleChangingRequiredFieldValidator()
> > > {
> > > this.helper = new StyleChangingHelper(this);
> > > }
> > >
> > > /// <summary>
> > > /// The control whose style should be changed when validation results
> > > in an invalid state.
> > > /// </summary>
> > > public string ControlToChange
> > > {
> > > get
> > > {
> > > return this.helper.ControlToChange;
> > > }
> > > set
> > > {
> > > this.helper.ControlToChange = value;
> > > }
> > > }
> > >
> > > /// <summary>
> > > /// The CSS class to use when changing the style of the targeted
> > > control.
> > > /// </summary>
> > > public string ChangeCssClass
> > > {
> > > get
> > > {
> > > return this.helper.ChangeCssClass;
> > > }
> > > set
> > > {
> > > this.helper.ChangeCssClass = value;
> > > }
> > > }
> > >
> > > /// <summary>
> > > /// Raises the Init event.
> > > /// </summary>
> > > /// <param name="e">An EventArgs object that contains the event
> > > data.</param>
> > > protected override void OnInit(System.EventArgs e)
> > > {
> > > base.OnInit(e);
> > > this.helper.OnInit(e);
> > > }
> > >
> > > /// <summary>
> > > /// Determines whether the value in the input control is valid.
> > > /// </summary>
> > > /// <returns><c>true</c> if the value in the input control is valid;
> > > otherwise, <c>false</c>.</returns>
> > > protected override bool EvaluateIsValid()
> > > {
> > > bool isValid = base.EvaluateIsValid();
> > > return this.helper.EvaluateIsValid(isValid);
> > > }
> > >
> > > /// <summary>
> > > /// Raises the PreRender event.
> > > /// </summary>
> > > /// <param name="e">An EventArgs object that contains the event
> > > data.</param>
> > > protected override void OnPreRender(System.EventArgs e)
> > > {
> > > this.helper.OnPreRender(e);
> > > base.OnPreRender(e);
> > > }
> > >
> > > /// <summary>
> > > /// Adds HTML attributes and styles that need to be rendered to the
> > > specified System.Web.UI.HtmlTextWriter.
> > > /// </summary>
> > > /// <param name="writer">A System.Web.UI.HtmlTextWriter that
> > > represents the output stream to render HTML content on the
> > > client.</param>
> > > protected override void AddAttributesToRender(HtmlTextWriter writer)
> > > {
> > > base.AddAttributesToRender(writer);
> > > this.helper.AddAttributesToRender(writer, this.RenderUplevel);
> > > }
> > > }
> > >
> > > We have created a StyleChangingHelper class, an instance of which is
> > > instantiated by each Validator derived subclass, and objects based on
> > > this class handle the writing of the attributes.
> > >
> > > /// <summary>
> > > /// Provides functionality for style changing validation controls.
> > > /// </summary>
> > > public class StyleChangingHelper
> > > {
> > > private BaseValidator validator;
> > > private string controlToChange;
> > > private string changeCssClass;
> > > private object foundControl;
> > > private string originalCssClass;
> > > private const string evaluationFunctionSuffix = "_Verify";
> > >
> > > /// <summary>
> > > /// Constructor which initialises the helper with a validator
> > > instance.
> > > /// </summary>
> > > /// <param name="validator">The validator that this helper will be
> > > helping.</param>
> > > public StyleChangingHelper(BaseValidator validator)
> > > {
> > > this.validator = validator;
> > > }
> > >
> > > /// <summary>
> > > /// The control whose style should be changed when validation results
> > > in an invalid state.
> > > /// </summary>
> > > public string ControlToChange
> > > {
> > > get
> > > {
> > > return this.controlToChange;
> > > }
> > > set
> > > {
> > > this.controlToChange = value;
> > > }
> > > }
> > >
> > > /// <summary>
> > > /// The CSS class to use when changing the style of the targeted
> > > control.
> > > /// </summary>
> > > public string ChangeCssClass
> > > {
> > > get
> > > {
> > > return this.changeCssClass;
> > > }
> > > set
> > > {
> > > this.changeCssClass = value;
> > > }
> > > }
> > >
> > > /// <summary>
> > > /// Should be called by the base validator upon raising the Init
> > > event.
> > > /// </summary>
> > > /// <param name="e">An EventArgs object that contains the event
> > > data.</param>
> > > public void OnInit(System.EventArgs e)
> > > {
> > >                               string controlID = DeriveId('$');
> > >
> > > this.foundControl = this.validator.Page.FindControl(controlID);
> > > if (this.foundControl != null)
> > > {
> > > if (this.foundControl is WebControl)
> > > {
> > > WebControl foundWebControl = (WebControl) this.foundControl;
> > > this.originalCssClass = foundWebControl.CssClass;
> > > }
> > > else if (foundControl is HtmlControl)
> > > {
> > > HtmlControl foundHtmlControl = (HtmlControl) this.foundControl;
> > > this.originalCssClass = foundHtmlControl.Attributes["class"];
> > > }
> > > }
> > > }
> > >
> > > /// <summary>
> > > /// Determines whether the value in the input control is valid.
> > > /// </summary>
> > > /// <param name="isValid">Indicates whether the calling validator
> > > considers the input control valid.</param>
> > > public bool EvaluateIsValid(bool isValid)
> > > {
> > > if (!isValid)
> > > {
> > > if (this.foundControl != null)
> > > {
> > > if (this.foundControl is WebControl)
> > > {
> > > WebControl foundWebControl = (WebControl) this.foundControl;
> > >
> > > foundWebControl.CssClass = this.changeCssClass;
> > > }
> > > else if (foundControl is HtmlControl)
> > > {
Author
24 Jun 2006 8:54 AM
Alessandro Zifiglio
hi Jeremy,
so its just as Jim clearly stated in the previous post. In your place, i
wont inherit the RequiredFieldValidator control. But write my own custom
validator. The requiredFieldValidator control does not do much anyway, and
there is minimum code for it. All the meat and postatoes of this controls
code is just registering in the AddAttributesToRender method, only that
un-needed expandoattribute that you want to exclude from your custom
implementatoin, defining your own. Since you want to write a customized
implementation, deriving from baseValidator is the way to go. Otherwise you
have to deal with the obstacles you are dealing with  now and also for
nothing.

Good luck,
Alessandro Zifiglio

Show quoteHide quote
"JimOx" <Ji***@discussions.microsoft.com> ha scritto nel messaggio
news:B3AD086D-DE1E-4DC2-97F8-6B37534C30B3@microsoft.com...
> Jeremy,
>
> I believe that to do this you can go one of two ways.  Either don't call
> the
> base.AddAttributesToRender in your overriding method.  This will require
> you
> to have to manually register all of the attributes that the base class
> would
> have registered that you need.  The other option is to inherit from
> BaseValidator instead of RequiredFieldValidator.  This is because
> BaseValidator does not register the
> "evaluationfunction" attribute but RequiredFieldValidator does and as far
> as
> I know once an ExpandoAttribute is registered there is no way to change
> it's
> value or remove the original.
>
> As a side note you will need to use
> Page.ClientScript.RegisterExpandoAttribute to write the attribute instead
> of
> writer.AddAttribute.  This is because if you use writer.AddAttribute it
> will
> work in IE but not FireFox.  However
> Page.ClientScript.RegisterExpandoAttribute will work in both.
>
> "jeremy.brews***@akqa.com" wrote:
>
>> Hi Alessando
>>
>> If I don't call the validator base.AddAttributesToRender then no aspect
>> of the validator gets written to the page.
>>
>> As you say, I am overriding the AddAttributesToRender method in my
>> custom validators and they do indeed call the StyleChangingHelper
>> instance variable's method of the same name.
>>
>> MSDN states "Notes to Inheritors When overriding the
>> AddAttributesToRender method, be sure to call the corresponding method
>> in the base class. Otherwise, the attributes contained in the base
>> class will not be rendered."
>>
>> Or are you suggesting that my override that does not call the base
>> implementation needs to do more than it is doing at the minute?
>>
>> The StyleChangingRequiredFieldValidator has the following OnPreRender
>> and AddAttributesToRender methods:
>>
>> /// <summary>
>> /// Raises the PreRender event.
>> /// </summary>
>> /// <param name="e">An EventArgs object that contains the event
>> data.</param>
>> protected override void OnPreRender(System.EventArgs e)
>> {
>> this.helper.OnPreRender(e);
>> base.OnPreRender(e);
>> }
>>
>> /// <summary>
>> /// Adds HTML attributes and styles that need to be rendered to the
>> specified System.Web.UI.HtmlTextWriter.
>> /// </summary>
>> /// <param name="writer">A System.Web.UI.HtmlTextWriter that represents
>> the output stream to render HTML content on the client.</param>
>> protected override void AddAttributesToRender(HtmlTextWriter writer)
>> {
>> base.AddAttributesToRender(writer);
>> this.helper.AddAttributesToRender(writer, this.RenderUplevel);
>> }
>>
>> The StyleChangingHelper has the following custom methods of the same
>> names:
>>
>> /// <summary>
>> /// Should be called by the base validator upon raising the PreRender
>> event.
>> /// </summary>
>> /// <param name="e">An EventArgs object that contains the event
>> data.</param>
>> public void OnPreRender(System.EventArgs e)
>> {
>> if (this.validator.EnableClientScript)
>> {
>> // this.validator.Attributes["evaluationfunction"] =
>> this.validator.GetType().Name + evaluationFunctionSuffix;
>> this.validator.Page.ClientScript.RegisterExpandoAttribute(validator.ClientID,
>> "evaluationfunction", this.validator.GetType().Name +
>> evaluationFunctionSuffix);
>> }
>> }
>>
>> /// <summary>
>> /// Adds HTML attributes and styles that need to be rendered to the
>> specified System.Web.UI.HtmlTextWriter.
>> /// </summary>
>> /// <param name="writer">A System.Web.UI.HtmlTextWriter that represents
>> the output stream to render HTML content on the client.</param>
>> /// <param name="renderUpLevel">Indicates whether the client's browser
>> supports uplevel rendering.</param>
>> public void AddAttributesToRender(HtmlTextWriter writer, bool
>> renderUpLevel)
>> {
>> if (renderUpLevel)
>> {
>> string renderedControlID;
>> renderedControlID = DeriveId('_');
>>
>> writer.AddAttribute("controltochange", renderedControlID);
>> writer.AddAttribute("changecssclass", ChangeCssClass);
>> writer.AddAttribute("originalcssclass", this.originalCssClass);
>> }
>> }
>>
>>
>> Alessandro Zifiglio wrote:
>> > hi Jeremy, in your override of AddAttributesToRender, do not call
>> > base.AddAttributesToRender. Instead what you need to do is override
>> > this
>> > method as you are currently doing and add apply your customized
>> > attributes
>> > to it, which is probably being done via the method call to your helper
>> > class.
>> >
>> > Regards,
>> > Alessandro Zifiglio
>> > <jeremy.brews***@akqa.com> ha scritto nel messaggio
>> > news:1151058013.109033.231650@m73g2000cwd.googlegroups.com...
>> > > Hi Jim
>> > >
>> > > Thanks for the reply.  This is something we are already doing.  We
>> > > have
>> > > subclassed each validator for which we want to create a customised
>> > > behaviour.  So we have a class with the following definition:
>> > >
>> > > public class StyleChangingRequiredFieldValidator :
>> > > RequiredFieldValidator
>> > > {
>> > > private StyleChangingHelper helper;
>> > >
>> > > /// <summary>
>> > > /// Default constructor.
>> > > /// </summary>
>> > > public StyleChangingRequiredFieldValidator()
>> > > {
>> > > this.helper = new StyleChangingHelper(this);
>> > > }
>> > >
>> > > /// <summary>
>> > > /// The control whose style should be changed when validation results
>> > > in an invalid state.
>> > > /// </summary>
>> > > public string ControlToChange
>> > > {
>> > > get
>> > > {
>> > > return this.helper.ControlToChange;
>> > > }
>> > > set
>> > > {
>> > > this.helper.ControlToChange = value;
>> > > }
>> > > }
>> > >
>> > > /// <summary>
>> > > /// The CSS class to use when changing the style of the targeted
>> > > control.
>> > > /// </summary>
>> > > public string ChangeCssClass
>> > > {
>> > > get
>> > > {
>> > > return this.helper.ChangeCssClass;
>> > > }
>> > > set
>> > > {
>> > > this.helper.ChangeCssClass = value;
>> > > }
>> > > }
>> > >
>> > > /// <summary>
>> > > /// Raises the Init event.
>> > > /// </summary>
>> > > /// <param name="e">An EventArgs object that contains the event
>> > > data.</param>
>> > > protected override void OnInit(System.EventArgs e)
>> > > {
>> > > base.OnInit(e);
>> > > this.helper.OnInit(e);
>> > > }
>> > >
>> > > /// <summary>
>> > > /// Determines whether the value in the input control is valid.
>> > > /// </summary>
>> > > /// <returns><c>true</c> if the value in the input control is valid;
>> > > otherwise, <c>false</c>.</returns>
>> > > protected override bool EvaluateIsValid()
>> > > {
>> > > bool isValid = base.EvaluateIsValid();
>> > > return this.helper.EvaluateIsValid(isValid);
>> > > }
>> > >
>> > > /// <summary>
>> > > /// Raises the PreRender event.
>> > > /// </summary>
>> > > /// <param name="e">An EventArgs object that contains the event
>> > > data.</param>
>> > > protected override void OnPreRender(System.EventArgs e)
>> > > {
>> > > this.helper.OnPreRender(e);
>> > > base.OnPreRender(e);
>> > > }
>> > >
>> > > /// <summary>
>> > > /// Adds HTML attributes and styles that need to be rendered to the
>> > > specified System.Web.UI.HtmlTextWriter.
>> > > /// </summary>
>> > > /// <param name="writer">A System.Web.UI.HtmlTextWriter that
>> > > represents the output stream to render HTML content on the
>> > > client.</param>
>> > > protected override void AddAttributesToRender(HtmlTextWriter writer)
>> > > {
>> > > base.AddAttributesToRender(writer);
>> > > this.helper.AddAttributesToRender(writer, this.RenderUplevel);
>> > > }
>> > > }
>> > >
>> > > We have created a StyleChangingHelper class, an instance of which is
>> > > instantiated by each Validator derived subclass, and objects based on
>> > > this class handle the writing of the attributes.
>> > >
>> > > /// <summary>
>> > > /// Provides functionality for style changing validation controls.
>> > > /// </summary>
>> > > public class StyleChangingHelper
>> > > {
>> > > private BaseValidator validator;
>> > > private string controlToChange;
>> > > private string changeCssClass;
>> > > private object foundControl;
>> > > private string originalCssClass;
>> > > private const string evaluationFunctionSuffix = "_Verify";
>> > >
>> > > /// <summary>
>> > > /// Constructor which initialises the helper with a validator
>> > > instance.
>> > > /// </summary>
>> > > /// <param name="validator">The validator that this helper will be
>> > > helping.</param>
>> > > public StyleChangingHelper(BaseValidator validator)
>> > > {
>> > > this.validator = validator;
>> > > }
>> > >
>> > > /// <summary>
>> > > /// The control whose style should be changed when validation results
>> > > in an invalid state.
>> > > /// </summary>
>> > > public string ControlToChange
>> > > {
>> > > get
>> > > {
>> > > return this.controlToChange;
>> > > }
>> > > set
>> > > {
>> > > this.controlToChange = value;
>> > > }
>> > > }
>> > >
>> > > /// <summary>
>> > > /// The CSS class to use when changing the style of the targeted
>> > > control.
>> > > /// </summary>
>> > > public string ChangeCssClass
>> > > {
>> > > get
>> > > {
>> > > return this.changeCssClass;
>> > > }
>> > > set
>> > > {
>> > > this.changeCssClass = value;
>> > > }
>> > > }
>> > >
>> > > /// <summary>
>> > > /// Should be called by the base validator upon raising the Init
>> > > event.
>> > > /// </summary>
>> > > /// <param name="e">An EventArgs object that contains the event
>> > > data.</param>
>> > > public void OnInit(System.EventArgs e)
>> > > {
>> > >                               string controlID = DeriveId('$');
>> > >
>> > > this.foundControl = this.validator.Page.FindControl(controlID);
>> > > if (this.foundControl != null)
>> > > {
>> > > if (this.foundControl is WebControl)
>> > > {
>> > > WebControl foundWebControl = (WebControl) this.foundControl;
>> > > this.originalCssClass = foundWebControl.CssClass;
>> > > }
>> > > else if (foundControl is HtmlControl)
>> > > {
>> > > HtmlControl foundHtmlControl = (HtmlControl) this.foundControl;
>> > > this.originalCssClass = foundHtmlControl.Attributes["class"];
>> > > }
>> > > }
>> > > }
>> > >
>> > > /// <summary>
>> > > /// Determines whether the value in the input control is valid.
>> > > /// </summary>
>> > > /// <param name="isValid">Indicates whether the calling validator
>> > > considers the input control valid.</param>
>> > > public bool EvaluateIsValid(bool isValid)
>> > > {
>> > > if (!isValid)
>> > > {
>> > > if (this.foundControl != null)
>> > > {
>> > > if (this.foundControl is WebControl)
>> > > {
>> > > WebControl foundWebControl = (WebControl) this.foundControl;
>> > >
>> > > foundWebControl.CssClass = this.changeCssClass;
>> > > }
>> > > else if (foundControl is HtmlControl)
>> > > {
Author
4 Jul 2006 12:11 PM
jeremy.brewster
Hi Jim, Alessandro

Thanks for your advice on this issue.  As you have both suggested I
have derived my required field validator directly from BaseValidator
and this is now working great.

I also had to create a regular expression validator and a compare
validator to derive from BaseValidator and these are also now working
great.

I had a few issues creating a "custom" custom validator to derive from
BaseValidator rather than the CustomValidator class with respect to
wiring up the server validation events for each type of custom
validator but this is also now working.

Thanks again for your advice.

Jez

Alessandro Zifiglio wrote:
Show quoteHide quote
> hi Jeremy,
> so its just as Jim clearly stated in the previous post. In your place, i
> wont inherit the RequiredFieldValidator control. But write my own custom
> validator. The requiredFieldValidator control does not do much anyway, and
> there is minimum code for it. All the meat and postatoes of this controls
> code is just registering in the AddAttributesToRender method, only that
> un-needed expandoattribute that you want to exclude from your custom
> implementatoin, defining your own. Since you want to write a customized
> implementation, deriving from baseValidator is the way to go. Otherwise you
> have to deal with the obstacles you are dealing with  now and also for
> nothing.
>
> Good luck,
> Alessandro Zifiglio
>
> "JimOx" <Ji***@discussions.microsoft.com> ha scritto nel messaggio
> news:B3AD086D-DE1E-4DC2-97F8-6B37534C30B3@microsoft.com...
> > Jeremy,
> >
> > I believe that to do this you can go one of two ways.  Either don't call
> > the
> > base.AddAttributesToRender in your overriding method.  This will require
> > you
> > to have to manually register all of the attributes that the base class
> > would
> > have registered that you need.  The other option is to inherit from
> > BaseValidator instead of RequiredFieldValidator.  This is because
> > BaseValidator does not register the
> > "evaluationfunction" attribute but RequiredFieldValidator does and as far
> > as
> > I know once an ExpandoAttribute is registered there is no way to change
> > it's
> > value or remove the original.
> >
> > As a side note you will need to use
> > Page.ClientScript.RegisterExpandoAttribute to write the attribute instead
> > of
> > writer.AddAttribute.  This is because if you use writer.AddAttribute it
> > will
> > work in IE but not FireFox.  However
> > Page.ClientScript.RegisterExpandoAttribute will work in both.
> >
> > "jeremy.brews***@akqa.com" wrote:
> >
> >> Hi Alessando
> >>
> >> If I don't call the validator base.AddAttributesToRender then no aspect
> >> of the validator gets written to the page.
> >>
> >> As you say, I am overriding the AddAttributesToRender method in my
> >> custom validators and they do indeed call the StyleChangingHelper
> >> instance variable's method of the same name.
> >>
> >> MSDN states "Notes to Inheritors When overriding the
> >> AddAttributesToRender method, be sure to call the corresponding method
> >> in the base class. Otherwise, the attributes contained in the base
> >> class will not be rendered."
> >>
> >> Or are you suggesting that my override that does not call the base
> >> implementation needs to do more than it is doing at the minute?
> >>
> >> The StyleChangingRequiredFieldValidator has the following OnPreRender
> >> and AddAttributesToRender methods:
> >>
> >> /// <summary>
> >> /// Raises the PreRender event.
> >> /// </summary>
> >> /// <param name="e">An EventArgs object that contains the event
> >> data.</param>
> >> protected override void OnPreRender(System.EventArgs e)
> >> {
> >> this.helper.OnPreRender(e);
> >> base.OnPreRender(e);
> >> }
> >>
> >> /// <summary>
> >> /// Adds HTML attributes and styles that need to be rendered to the
> >> specified System.Web.UI.HtmlTextWriter.
> >> /// </summary>
> >> /// <param name="writer">A System.Web.UI.HtmlTextWriter that represents
> >> the output stream to render HTML content on the client.</param>
> >> protected override void AddAttributesToRender(HtmlTextWriter writer)
> >> {
> >> base.AddAttributesToRender(writer);
> >> this.helper.AddAttributesToRender(writer, this.RenderUplevel);
> >> }
> >>
> >> The StyleChangingHelper has the following custom methods of the same
> >> names:
> >>
> >> /// <summary>
> >> /// Should be called by the base validator upon raising the PreRender
> >> event.
> >> /// </summary>
> >> /// <param name="e">An EventArgs object that contains the event
> >> data.</param>
> >> public void OnPreRender(System.EventArgs e)
> >> {
> >> if (this.validator.EnableClientScript)
> >> {
> >> // this.validator.Attributes["evaluationfunction"] =
> >> this.validator.GetType().Name + evaluationFunctionSuffix;
> >> this.validator.Page.ClientScript.RegisterExpandoAttribute(validator.ClientID,
> >> "evaluationfunction", this.validator.GetType().Name +
> >> evaluationFunctionSuffix);
> >> }
> >> }
> >>
> >> /// <summary>
> >> /// Adds HTML attributes and styles that need to be rendered to the
> >> specified System.Web.UI.HtmlTextWriter.
> >> /// </summary>
> >> /// <param name="writer">A System.Web.UI.HtmlTextWriter that represents
> >> the output stream to render HTML content on the client.</param>
> >> /// <param name="renderUpLevel">Indicates whether the client's browser
> >> supports uplevel rendering.</param>
> >> public void AddAttributesToRender(HtmlTextWriter writer, bool
> >> renderUpLevel)
> >> {
> >> if (renderUpLevel)
> >> {
> >> string renderedControlID;
> >> renderedControlID = DeriveId('_');
> >>
> >> writer.AddAttribute("controltochange", renderedControlID);
> >> writer.AddAttribute("changecssclass", ChangeCssClass);
> >> writer.AddAttribute("originalcssclass", this.originalCssClass);
> >> }
> >> }
> >>
> >>
> >> Alessandro Zifiglio wrote:
> >> > hi Jeremy, in your override of AddAttributesToRender, do not call
> >> > base.AddAttributesToRender. Instead what you need to do is override
> >> > this
> >> > method as you are currently doing and add apply your customized
> >> > attributes
> >> > to it, which is probably being done via the method call to your helper
> >> > class.
> >> >
> >> > Regards,
> >> > Alessandro Zifiglio
> >> > <jeremy.brews***@akqa.com> ha scritto nel messaggio
> >> > news:1151058013.109033.231650@m73g2000cwd.googlegroups.com...
> >> > > Hi Jim
> >> > >
> >> > > Thanks for the reply.  This is something we are already doing.  We
> >> > > have
> >> > > subclassed each validator for which we want to create a customised
> >> > > behaviour.  So we have a class with the following definition:
> >> > >
> >> > > public class StyleChangingRequiredFieldValidator :
> >> > > RequiredFieldValidator
> >> > > {
> >> > > private StyleChangingHelper helper;
> >> > >
> >> > > /// <summary>
> >> > > /// Default constructor.
> >> > > /// </summary>
> >> > > public StyleChangingRequiredFieldValidator()
> >> > > {
> >> > > this.helper = new StyleChangingHelper(this);
> >> > > }
> >> > >
> >> > > /// <summary>
> >> > > /// The control whose style should be changed when validation results
> >> > > in an invalid state.
> >> > > /// </summary>
> >> > > public string ControlToChange
> >> > > {
> >> > > get
> >> > > {
> >> > > return this.helper.ControlToChange;
> >> > > }
> >> > > set
> >> > > {
> >> > > this.helper.ControlToChange = value;
> >> > > }
> >> > > }
> >> > >
> >> > > /// <summary>
> >> > > /// The CSS class to use when changing the style of the targeted
> >> > > control.
> >> > > /// </summary>
> >> > > public string ChangeCssClass
> >> > > {
> >> > > get
> >> > > {
> >> > > return this.helper.ChangeCssClass;
> >> > > }
> >> > > set
> >> > > {
> >> > > this.helper.ChangeCssClass = value;
> >> > > }
> >> > > }
> >> > >
> >> > > /// <summary>
> >> > > /// Raises the Init event.
> >> > > /// </summary>
> >> > > /// <param name="e">An EventArgs object that contains the event
> >> > > data.</param>
> >> > > protected override void OnInit(System.EventArgs e)
> >> > > {
> >> > > base.OnInit(e);
> >> > > this.helper.OnInit(e);
> >> > > }
> >> > >
> >> > > /// <summary>
> >> > > /// Determines whether the value in the input control is valid.
> >> > > /// </summary>
> >> > > /// <returns><c>true</c> if the value in the input control is valid;
> >> > > otherwise, <c>false</c>.</returns>
> >> > > protected override bool EvaluateIsValid()
> >> > > {
> >> > > bool isValid = base.EvaluateIsValid();
> >> > > return this.helper.EvaluateIsValid(isValid);
> >> > > }
> >> > >
> >> > > /// <summary>
> >> > > /// Raises the PreRender event.
> >> > > /// </summary>
> >> > > /// <param name="e">An EventArgs object that contains the event
> >> > > data.</param>
> >> > > protected override void OnPreRender(System.EventArgs e)
> >> > > {
> >> > > this.helper.OnPreRender(e);
> >> > > base.OnPreRender(e);
> >> > > }
> >> > >
> >> > > /// <summary>
> >> > > /// Adds HTML attributes and styles that need to be rendered to the
> >> > > specified System.Web.UI.HtmlTextWriter.
> >> > > /// </summary>
> >> > > /// <param name="writer">A System.Web.UI.HtmlTextWriter that
> >> > > represents the output stream to render HTML content on the
> >> > > client.</param>
> >> > > protected override void AddAttributesToRender(HtmlTextWriter writer)
> >> > > {
> >> > > base.AddAttributesToRender(writer);
> >> > > this.helper.AddAttributesToRender(writer, this.RenderUplevel);
> >> > > }
> >> > > }
> >> > >
> >> > > We have created a StyleChangingHelper class, an instance of which is
> >> > > instantiated by each Validator derived subclass, and objects based on
> >> > > this class handle the writing of the attributes.
> >> > >
> >> > > /// <summary>
> >> > > /// Provides functionality for style changing validation controls.
> >> > > /// </summary>
> >> > > public class StyleChangingHelper
> >> > > {
> >> > > private BaseValidator validator;
> >> > > private string controlToChange;
> >> > > private string changeCssClass;
> >> > > private object foundControl;
> >> > > private string originalCssClass;
> >> > > private const string evaluationFunctionSuffix = "_Verify";
> >> > >
> >> > > /// <summary>
> >> > > /// Constructor which initialises the helper with a validator
> >> > > instance.
> >> > > /// </summary>
> >> > > /// <param name="validator">The validator that this helper will be
> >> > > helping.</param>
> >> > > public StyleChangingHelper(BaseValidator validator)
> >> > > {
> >> > > this.validator = validator;
> >> > > }
> >> > >
> >> > > /// <summary>
> >> > > /// The control whose style should be changed when validation results
> >> > > in an invalid state.
> >> > > /// </summary>
> >> > > public string ControlToChange
> >> > > {
> >> > > get
> >> > > {
> >> > > return this.controlToChange;
> >> > > }
> >> > > set
> >> > > {
> >> > > this.controlToChange = value;
> >> > > }
> >> > > }
> >> > >
> >> > > /// <summary>
> >> > > /// The CSS class to use when changing the style of the targeted
> >> > > control.
> >> > > /// </summary>
> >> > > public string ChangeCssClass
> >> > > {
> >> > > get
> >> > > {
> >> > > return this.changeCssClass;
> >> > > }
> >> > > set
> >> > > {
> >> > > this.changeCssClass = value;
> >> > > }
> >> > > }
> >> > >
> >> > > /// <summary>
> >> > > /// Should be called by the base validator upon raising the Init
> >> > > event.
> >> > > /// </summary>
> >> > > /// <param name="e">An EventArgs object that contains the event
> >> > > data.</param>
> >> > > public void OnInit(System.EventArgs e)
> >> > > {
> >> > >                               string controlID = DeriveId('$');
> >> > >
> >> > > this.foundControl = this.validator.Page.FindControl(controlID);
> >> > > if (this.foundControl != null)
> >> > > {
> >> > > if (this.foundControl is WebControl)
> >> > > {
> >> > > WebControl foundWebControl = (WebControl) this.foundControl;
> >> > > this.originalCssClass = foundWebControl.CssClass;
> >> > > }
> >> > > else if (foundControl is HtmlControl)
> >> > > {
> >> > > HtmlControl foundHtmlControl = (HtmlControl) this.foundControl;
> >> > > this.originalCssClass = foundHtmlControl.Attributes["class"];
> >> > > }
> >> > > }
> >> > > }
> >> > >
> >> > > /// <summary>
> >> > > /// Determines whether the value in the input control is valid.
> >> > > /// </summary>
> >> > > /// <param name="isValid">Indicates whether the calling validator
> >> > > considers the input control valid.</param>
> >> > > public bool EvaluateIsValid(bool isValid)
> >> > > {
> >> > > if (!isValid)
> >> > > {
> >> > > if (this.foundControl != null)
> >> > > {
> >> > > if (this.foundControl is WebControl)
> >> > > {
> >> > > WebControl foundWebControl = (WebControl) this.foundControl;
> >> > >
> >> > > foundWebControl.CssClass = this.changeCssClass;
> >> > > }
> >> > > else if (foundControl is HtmlControl)
> >> > > {
Author
27 Aug 2006 12:09 PM
Ryan Garaygay
Hi guys, had a similar problem.

I tried to override the AddAttributesToRender and
RegisterExpandoAttribute as mentioned but when I use my control on a
page, I'm getting a "an entry with the same key already exists
exception"

I only get the error when overriding the AddAttributesToRender. I don't
call the base method and I'm inheriting BaseValidator.

Any thoughts? Thanks in advance

*** Sent via Developersdex http://www.developersdex.com ***

Bookmark and Share

Post Thread options