views:

1292

answers:

2

I have a class that looks like this:

public class TextField : TextBox
{
   public bool Required { get; set; }
   RequiredFieldValidator _validator;

   protected override void CreateChildControls()
   {
      base.CreateChildControls();


      _validator = new RequiredFieldValidator();
      _validator.ControlToValidate = this.ID;
      if(Required)
          Controls.Add(_validator);
   }

   public override void Render(HtmlTextWriter tw)
   {
      base.Render(tw);

      if(Required)
         _validator.RenderControl(tw);
   }
}

This has been working for a while in a internal application where javascript is always enabled. I recently noticed that an upstream javascript error can prevent the validators from firing, so the server side validation should kick in... right? right?

So the Page.IsValid property always returns true (I even tried explicitly calling Page.Validate() before-hand).

After some digging, I found that the validator init method should add the validator to the page, but due to the way I'm building it up, I don't think this ever happens. Thus, client side validation works, but server side validation does not.

I've tried this:

protected override OnInit()
{
   base.OnInit();

   Page.Validators.Add(_validator); // <-- validator is null here
}

But of course the validator is null here (and sometimes it's not required so it shouldn't be added)... but OnInit() is really early for me to make those decisions (the Required property won't have been loaded from ViewState for example).

Ideas?

A: 

Validators have to inherit from BaseValidator.

David Kemp
I'm not writing my own validator, I'm using the RequiredFieldValidator.
Ben Scheirman
TextBox isn't a Composite control, and your control doesn't inherit from BaseValidator, so the framework will never find your validator.You can either rewrite your control as a CompositeControl, or as a BaseValidator. Your implementation will never work.
David Kemp
If the control is added to the controls collection, then the lifecycle will run, and the validator should add itself ot the page.validators collection on init.
Ben Scheirman
the other reason why I don't want to create this as a composite control is because it needs to integrate with other components that work on TextBox controls (such as the extender controls in ASP.NET AJAX toolkit)
Ben Scheirman
+1  A: 

The CreateChildControls is basically for the controls that have childs. RequiredFieldValidator is like a sibling to TextBox.

Here is the code that works for me:

public class RequiredTextBox : TextBox
    {
        private RequiredFieldValidator _req;
        private string _errorMessage;

        public string ErrorMessage
        {
            get { return _errorMessage; }
            set { _errorMessage = value; } 
        }

        protected override void OnInit(EventArgs e)
        {
            _req = new RequiredFieldValidator();
            _req.ControlToValidate = this.ID;
            _req.ErrorMessage = _errorMessage;
            Controls.Add(_req);
            base.OnInit(e); 
        }       

        protected override void Render(System.Web.UI.HtmlTextWriter writer)
        {
            base.Render(writer);
            _req.RenderControl(writer); 
        }
    }

And here it the ASP.NET page behind:

 protected void SubmitClick(object sender, EventArgs e)
        {
            if(Page.IsValid)
            {
                // do something
            }
        }

And here is the ASPX code:

 <MyControl:RequiredTextBox runat="server" ErrorMessage="Name is required!" ID="txtName"></MyControl:RequiredTextBox>

    <asp:Button ID="Btn_Submit" runat="server" Text="Submit" OnClick="SubmitClick" />
azamsharp
Actually, what worked for me using your sample as a guide is to just call EnsureChildControls() before the base.OnInit(e) call. Thanks!
Ben Scheirman