Link to home
Start Free TrialLog in
Avatar of thedude112286
thedude112286

asked on

Dynamic controls

I am developing a dynamic web control.  Right now, I'm just trying to get a (I thought) simple control to request a password, fire an event if it's correct, and write a failure message if it's wrong.  It works fine if I enter the right password, but if I enter the wrong password, my failure message never shows up.  

Basically, I set the viewstate to indicate whether or not to show the failure message, create all controls in an overrided CreateChildControls, and call EnsureChildControls whenever I want them to show up.  What am I doing wrong?

Here is the code:

using System;
      using System.Web.UI;
      using System.Web.UI.WebControls;
      
      
      /// <summary>
      /// Handles admin password request and authentication.
      /// </summary>
      public class AdminPasswordControl : WebControl {
            readonly string pwdTB_ID = "AdminPwdTB";
            readonly string pwdButton_ID = "AdminPwd";
            readonly string thisState = "AdminPasswordRequestControlState";
            enum States {
                  Clear, Failed
            }
            
            public event EventHandler PasswordAccepted;
            
            public AdminPasswordControl() {
                  this.EnableViewState = true;
                  ViewState.Add(thisState, States.Clear);
                  
                  Config.Instance.Sha1jsUrl = "sha1.js";
                  
                  System.Security.Cryptography.SHA1 sha1 = new System.Security.Cryptography.SHA1CryptoServiceProvider();
                  byte[] hash = sha1.ComputeHash(System.Text.Encoding.UTF8.GetBytes("pwd"));
                  Config.Instance.AdminPassword = Convert.ToBase64String(hash).Replace("=", String.Empty);
                  
                  EnsureChildControls();
            }
            
            public void OnSubmit(object sender, EventArgs e) {
                  Button btn = (Button)sender;
                  
                  string sha1EnteredPwd = ((TextBox)this.FindControl(pwdTB_ID)).Text;
                  
                  if ( Config.Instance.AdminPassword == sha1EnteredPwd ) {
                        if ( PasswordAccepted != null ) {
                              PasswordAccepted(this, new EventArgs());
                        }
                  }
                  else {
                        ViewState[thisState] = States.Failed;

                        EnsureChildControls();
                  }
            }
            
            protected override void CreateChildControls() {
                  this.Controls.Clear();
                  
                  this.Controls.Add(new JavascriptIncludeControl(Config.Instance.Sha1jsUrl));
                  
                  this.Controls.Add(ControlProvider.GetRegularLabel("Enter administrator password: "));
                  
                  TextBox pwdTb = new TextBox();
                  pwdTb.ID = pwdTB_ID;
                  pwdTb.TextMode = TextBoxMode.Password;
                  pwdTb.Width = ControlProvider.InputControlSize;
                  
                  this.Controls.Add(pwdTb);
                  this.Controls.Add(new LineBreakControl());
                  
                  Button submitBtn = ControlProvider.GetUpdateButton(pwdButton_ID,
                                                                     new EventHandler(OnSubmit));
                  submitBtn.Text = "Submit";
                  // Hash the password before sending
                  submitBtn.Attributes.Add("onClick", pwdTb.ClientID + ".value = " +
                                           "b64_sha1(" + pwdTb.ClientID + ".value);");
                  
                  this.Controls.Add(submitBtn);

                  if ( (States)ViewState[thisState] == States.Failed ) {
                        Label failLabel = ControlProvider.GetRegularLabel("Invalid password!");
                        failLabel.ForeColor = System.Drawing.Color.Red;
      
                        this.Controls.Add(failLabel);
                  }
            }
      }
Avatar of laotzi2000
laotzi2000

maybe OnSubmit execute after CreateChildControls, not before.
Have you checked that?
what is the value of ViewState[thisState], looks like it doesn't get equal

or what's ControlProvider.GetRegularLabel, what if you try like this..?

 if ((States)ViewState[thisState] == States.Failed) {
                    Label failLabel = new Label();
                    failLabel.Text="Invalid Password!";
                    failLabel.ForeColor = System.Drawing.Color.Red;
     
                    this.Controls.Add(failLabel);
 }
where is this come from...? I mean value of thisState variable, have you checked if it's right...?

ViewState[thisState]
Avatar of thedude112286

ASKER

ControlProvider.GetRegularLabel just returns a label whose appearance (width, height, etc) is already set.  This cut down on a lot of redundant code.  I'm pretty sure that the ViewState does get set to States.Failed, but I'll double check this tonight.  Is there anything wrong with the pattern used?  That is, when I want to update the interface, should I just set the viewstate and then call EnsureChildControls or is there a better way to do this?
laotzi, I call EnsureChildControls from OnSubmit so I just assumed that CreateChildControls would be called then.  If it's being called before, is there any way that I can have it called after OnSubmit?  Should I just add on the Login Failed label in the OnSubmit routine?
laotzi, I have also tried calling Controls.Clear before EnsureChildControls from OnSubmit and when I do that, I end up with a blank page.  This makes me think you are right about the order of execution.  How can I fix this???
ASKER CERTIFIED SOLUTION
Avatar of laotzi2000
laotzi2000

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
also remember that EnsureChildControls should be called after all controls are initialized on the form
Thanks laotzi.  I'll try that out.

davidlars99: If I initialize all of the controls before I call EnsureChildControls, what should CreatChildControls do?  Is it even needed?