Results 1 to 7 of 7

Thread: Custom control Properties

  1. #1

    Thread Starter
    Not NoteMe SLH's Avatar
    Join Date
    Mar 2002
    Location
    192.168.0.1 Preferred Animal: Penguin Reason for errors: Line#38
    Posts
    3,051

    Custom control Properties

    I've got a custom control as listed below (in C#)

    Code:
    public class LoginControl : System.Web.UI.WebControls.WebControl
     	{
     		private System.Web.UI.WebControls.TextBox txtusername = new TextBox();
     		private System.Web.UI.WebControls.TextBox txtpassword = new TextBox();
     		private System.Web.UI.WebControls.Button cmdLogon = new Button();
     		private System.Web.UI.WebControls.RequiredFieldValidator reqUsername = new RequiredFieldValidator();
     		private System.Web.UI.WebControls.RegularExpressionValidator revPassword = new RegularExpressionValidator();
     
     		[Bindable(true),Category("TextBoxContents")]
     		public string Username
     		{
     			get
     			{
     				return txtusername.Text;
     			}
     			set
     			{
     				txtusername.Text = value;
     			}
     		}
     		public string Password{
     			get
     			{
     				return txtpassword.Text;
     			}
     			set
     			{
     				txtpassword.Text = value;
     			}
     		}
     		
     		public LoginControl()
     		{
     			txtusername.Width = 140;
     			txtpassword.Width = 140;
     			txtusername.MaxLength = 15;
     			txtpassword.MaxLength = 15;
     			txtusername.TextMode = TextBoxMode.SingleLine;
     			txtpassword.TextMode = TextBoxMode.Password;
     
     			cmdLogon.Text = "Logon";
     			cmdLogon.Attributes.Add("OnServerClick","Submit_Click");
     			
     			//reqUsername.Text = "Username must not be blank";
     			reqUsername.Display = ValidatorDisplay.Dynamic;
     			reqUsername.EnableClientScript = true;
     			reqUsername.ErrorMessage = "Username must not be blank";
     			reqUsername.ControlToValidate = "txtusername";
     			reqUsername.Visible = false;
     
     			revPassword.Display = ValidatorDisplay.Dynamic;
     			revPassword.EnableClientScript = true;
     		    revPassword.ErrorMessage = "Password must be at least 6 alpha-numeric charactors";
     			revPassword.ControlToValidate = "txtpassword";
     			revPassword.Visible = false;
     		}
     		
     		/// <summary>
     		/// Render this control to the output parameter specified.
     		/// </summary>
     		/// <param name="output"> The HTML writer to write out to </param>
     		protected override void Render(HtmlTextWriter output)
     		{
     			output.Write("<table border=\"1\" width=\"300\" id=\"table1\">");
     			output.Write("<tr border=\"0\">");
     			output.Write("<td border=\"0\">Username:</td>");
     			output.Write("<td border=\"0\">");
     			txtusername.RenderControl(output);
     			output.Write("</td>");
     			output.Write("</tr>");
     			output.Write("<tr border=\"0\">");
     			output.Write("<td border=\"0\">Password:</td>");
     			output.Write("<td border=\"0\">");
     			txtpassword.RenderControl(output);
     			output.Write("</td>");
     			output.Write("</tr>");
     		    output.Write("<tr border=\"0\"><td colspan=\"2\"><div align=\"centre\">");
     			cmdLogon.RenderControl(output);
     			output.Write("<br>");
     			reqUsername.RenderControl(output);
     			output.Write("<br>");
     			revPassword.RenderControl(output);
     			output.Write("</div></td></tr>");
     			output.Write("</table>");
     		}
     	}
    When i put it on my page i can change the username and password properties at design time.

    Page code is below:

    Code:
    <%@ Page Language="C#" %>
     <%@ Register TagPrefix="n0" Namespace="George" Assembly="LoginControl" %>
     <%@ import Namespace="System.Data" %>
     <%@ import Namespace="System.Data.SqlClient" %>
     <%@ import Namespace="System.Web.Security" %>
     <script runat="server">
     
     	private void Page_Load(Object sender, EventArgs E)
     	{
     		 Page.Validate();
     		 if ((Page.IsPostBack) && (Page.IsValid))
     		 {
     			 SqlConnection myConnection = new SqlConnection("server=GEORGE;database=MyDB;Trusted_Connection=yes");
     			 SqlCommand myCommand = new SqlCommand("SELECT People.Nickname, People.Password FROM People WHERE People.Nickname='" + ctrlLogin.Username + "'", myConnection);
     			 try
     			 {
     				 myConnection.Open();
     				 SqlDataReader dr = myCommand.ExecuteReader();
     				 if(dr.Read())
     				 {
     					 if(dr.GetString(1).Trim() == ctrlLogin.Password.Trim())
     						 FormsAuthentication.RedirectFromLoginPage(ctrlLogin.Username, false);
     					 else
     						 Message.Text = "Sorry! Your password is incorrect.</br>Please log in again.";
     				 }
     				 else
     					 Message.Text = "Your username is wrong!</br>Please log in again.";
     			 }
     			 catch(Exception myException)
     			 {
     				 Response.Write("Oops! The error: " + myException.Message + " occured.");
     			 }
     			 finally
     			 {
     				 myConnection.Close();
     			 }
     			 Message.Text = "SELECT People.Nickname, People.Password FROM People WHERE People.Nickname='" + ctrlLogin.Username + "'";
     		 }
     	}
     
     </script>
     <html>
     <head>
     </head>
     <body style="FONT-FAMILY: arial">
     	<form runat="server">
     		<p>
     		    &nbsp;<n0:LoginControl id="ctrlLogin" runat="server"></n0:LoginControl>
     		</p>
     		<p>
     		    <asp:Label id="Message" runat="server">Label</asp:Label>
     		</p>
     	</form>
     </body>
     </html>
    If i change them at run time it doesn't work. It's as if it's still retrieving the old value (blank) when i do ctrlLogin.Username

    If i fill in the username and password at design time it works ok, however if i leave them blank, and type them in at runtime it doesn't work.

    Any ideas why this is happening?
    Quotes:
    "I am getting better then you guys.." NoteMe, on his leet english skills.
    "And I am going to meat her again later on tonight." NoteMe
    "I think you should change your name to QuoteMe" Shaggy Hiker, regarding NoteMe
    "my sweet lord jesus. I've decided never to have breast implants" Tom Gibbons
    Have I helped you? Please Rate my posts.


  2. #2
    I wonder how many charact
    Join Date
    Feb 2001
    Location
    Savage, MN, USA
    Posts
    3,704

    Re: Custom control Properties

    I don't have an IDE available to debug your code...

    but from experience that I've had... may I make some suggestions:

    1) Your GET/SET accessors for the UserName and Password properties should not directly set the textbox's text. They should set private variables that are also stored into Viewstate. At some point in the render (or preferably the prerender method), you can read the private variable and assign the textbox's text.

    Code:
    //add this to the declerations section
    private const string _usernameStateKey = "usrnm";
    private const string _passwordStateKey = "pswrd";
    
    private string _username = null;
    private string _password = null;
    
    
    //replace username/password properties with the following
    [Bindable(true),Category("TextBoxContents")]
     		public string Username
     		{
     			get
     			{
                                    if (ViewState[_usernameStateKey] != null)
                                          return (string)ViewState[_usernameStateKey];
     				else
                                          return _username;
     			}
     			set
     			{
     				_username = value;
                                    ViewState.Add([_usernameStateKey,value);
     			}
     		}
     		public string Password{
     			get
     			{
                                    if (ViewState[_passwordStateKey] != null)
                                         return (string)ViewState[_passwordStateKey];
                                    else
     				     return _password; 			}
     			set
     			{
     				_password = value;
                                    ViewState.Add([_passwordStateKey, value);
     			}
     		}
    
    //set the textbox's text here
                    private override PreRender(...)
                    {
                         EnsureChildControls();
                         txtusername.Text = ViewState[_usernameStateKey] == null ? _username : (string) ViewState[_usernameStateKey];
                         txtpassword.Text = (ViewState[_passwordStateKey] == null ? 
     _password : (string) ViewState[_passwordStateKey];
                    }
    
    //override createchildcontrols
                    private override void CreateChildControls()
                    {
                     txtusername = new TextBox();
                     txtpassword = new TextBox();
                     requiredvalidatorUsername = new requiredfieldvalidator();
                     ...
                      //set any properties that are not defaults here
                     txtpassword.TextMode = TextMode.Password;
                      
                      //you then must add the controls to the container
                     this.Controls.Add(txtusername);
                     this.Controls.Add(txtpassword);
                      this.Controls.Add(requiredvalidatorUsername);
                      ....
                    }
                     
                    }
    As you may have noticed, I've added an override CreateChildControls method. Simply, you should not create instances of the child controls in the declarations section, they should instead be moved to (preferably) the CreateChildControls method.


    Lastly, any control property that is defaulted to a specific attribute, does not need to be explicity set. For instance, txtusername.textmode = SingleLine is unnecessary, as this is the default for the framework, and kills processing time (even though the processing time is trivial, if this app serves 1000 clients a minute, every little bit will help).

  3. #3

    Thread Starter
    Not NoteMe SLH's Avatar
    Join Date
    Mar 2002
    Location
    192.168.0.1 Preferred Animal: Penguin Reason for errors: Line#38
    Posts
    3,051

    Re: Custom control Properties

    Thanks for your reply.

    I've changed the code as per your recommendations, listed below:

    Code:
    public class LoginControl : System.Web.UI.WebControls.WebControl
     	{
     		private const string _usernameStateKey = "usrnm";
     		private const string _passwordStateKey = "pswrd";
     
     		private string _username;
     		private string _password;
     		
     		private System.Web.UI.WebControls.TextBox txtusername = null;
     		private System.Web.UI.WebControls.TextBox txtpassword = null;
     		private System.Web.UI.WebControls.Button cmdLogon = null;
     		private System.Web.UI.WebControls.RequiredFieldValidator reqUsername = null;
     		private System.Web.UI.WebControls.RegularExpressionValidator revPassword = null;
     
     		[Bindable(true),Category("TextBoxContents")]
     		public string Username
     		{
     			get
     			{
     				if (ViewState[_usernameStateKey] != null)
     		    		return (string)ViewState[_usernameStateKey];
     				else
     					return _username;
     			}
     			set
     			{
     				_username = value;
     				ViewState.Add(_usernameStateKey,value);
     			}
     		}
     		public string Password
     		{
     			get
     			{
     				if (ViewState[_passwordStateKey] != null)
     		    		return (string)ViewState[_passwordStateKey];
     				else
     					return _password;
     			}
     			set
     			{
     				_password = value;
     				ViewState.Add(_passwordStateKey, value);
     			}
     		}
     
     		public new void PreRender()
     		{
     			EnsureChildControls();
     		    txtusername.Text = ViewState[_usernameStateKey] == null ? _username : (string) ViewState[_usernameStateKey];
     		    txtpassword.Text = ViewState[_passwordStateKey] == null ? _password : (string) ViewState[_passwordStateKey];
     		}
     
     		protected override void CreateChildControls()
     		{
     			txtusername = new TextBox();
     			txtpassword = new TextBox();
     			cmdLogon = new Button();
     			reqUsername = new RequiredFieldValidator();
     			revPassword = new RegularExpressionValidator();
     			txtusername.ID = "txtusername";
     			
     			txtpassword.TextMode = TextBoxMode.Password;
     			cmdLogon.Text = "Logon";
     			txtusername.Width = 140;
     			txtpassword.Width = 140;
     			txtusername.MaxLength = 15;
     			txtpassword.MaxLength = 15;
     			txtpassword.TextMode = TextBoxMode.Password;
     			txtpassword.ID = "txtpassword";
     
     			cmdLogon.Text = "Logon";
     			cmdLogon.Attributes.Add("OnServerClick","Submit_Click");
     			
     			reqUsername.Display = ValidatorDisplay.Dynamic;
     			reqUsername.EnableClientScript = true;
     			reqUsername.ErrorMessage = "Username must not be blank";
     			reqUsername.ControlToValidate = "txtusername";
     
     			revPassword.Display = ValidatorDisplay.Dynamic;
     			revPassword.EnableClientScript = true;
     		    revPassword.ErrorMessage = "Password must be at least 6 alpha-numeric charactors";
     			revPassword.ControlToValidate = "txtpassword";
     			
     			this.Controls.Add(txtusername);
     			this.Controls.Add(txtpassword);
     			this.Controls.Add(reqUsername);
     			this.Controls.Add(revPassword);
     		}
     		
     		/// <summary>
     		/// Render this control to the output parameter specified.
     		/// </summary>
     		/// <param name="output"> The HTML writer to write out to </param>
     		protected override void Render(HtmlTextWriter output)
     		{
     			output.Write("<table border=\"1\" width=\"300\" id=\"table1\">");
     			output.Write("<tr border=\"0\">");
     			output.Write("<td border=\"0\">Username:</td>");
     			output.Write("<td border=\"0\">");
     			txtusername.RenderControl(output);
     			output.Write("</td>");
     			output.Write("</tr>");
     			output.Write("<tr border=\"0\">");
     			output.Write("<td border=\"0\">Password:</td>");
     			output.Write("<td border=\"0\">");
     			txtpassword.RenderControl(output);
     			output.Write("</td>");
     			output.Write("</tr>");
     		    output.Write("<tr border=\"0\"><td colspan=\"2\"><div align=\"centre\">");
     			cmdLogon.RenderControl(output);
     			output.Write("<br>");
     			reqUsername.RenderControl(output);
     			output.Write("<br>");
     			revPassword.RenderControl(output);
     			output.Write("</div></td></tr>");
     			output.Write("</table>");
     		}
     	}
    However, i still get the same problem, except that now if i change the property at design time, when running it i get an object reference not set error.

    Any help would be greatly appreciated.
    Quotes:
    "I am getting better then you guys.." NoteMe, on his leet english skills.
    "And I am going to meat her again later on tonight." NoteMe
    "I think you should change your name to QuoteMe" Shaggy Hiker, regarding NoteMe
    "my sweet lord jesus. I've decided never to have breast implants" Tom Gibbons
    Have I helped you? Please Rate my posts.


  4. #4
    I wonder how many charact
    Join Date
    Feb 2001
    Location
    Savage, MN, USA
    Posts
    3,704

    Re: Custom control Properties

    Sorry I haven't responded (moved to a new house).

    I also forgot to tell you to implement the INaming Container.
    Code:
    public class LoginControl : System.Web.UI.WebControls.WebControl, INaming
    As far as the errors you receive when using the VS Designer:

    WebControls are not 'run' when viewed in the designer per se. You need to add a second class that inherits System.Web.UI.Design.ControlDesigner.

    You need to override the GetDesignTimeHtml() method.

    The following MSDN reference has a good example of how to do that under the 'Creating A Custom Designer' heading.

    http://msdn.microsoft.com/library/de...ebcontrols.asp

  5. #5

    Thread Starter
    Not NoteMe SLH's Avatar
    Join Date
    Mar 2002
    Location
    192.168.0.1 Preferred Animal: Penguin Reason for errors: Line#38
    Posts
    3,051

    Re: Custom control Properties

    Thanks for your reply.

    I couldn't find what you ment with the INaming container, i get a syntax error when adding it, and i did a search on MSDN but found nothing.

    Regarding the extra class, i've implemented it as below, but now i get nothing appearing in the designer (looks as though the control isn't there).

    Code:
    using System;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.ComponentModel;
    using System.Web.UI.Design;
    using System.IO;
    
    namespace George
    {
    	/// <summary>
    	/// A control containing a username, password and logon button
    	/// </summary>
    	[Designer("George.LoginControlDesigner, George"), DefaultProperty("Text"),
    		ToolboxData("<{0}:LoginControl runat=server></{0}:LoginControl>")]
    	public class LoginControl : System.Web.UI.WebControls.WebControl
    	{
    		private const string _usernameStateKey = "usrnm";
    		private const string _passwordStateKey = "pswrd";
    
    		private string _username;
    		private string _password;
    		
    		public System.Web.UI.WebControls.TextBox txtusername = null;
    		public System.Web.UI.WebControls.TextBox txtpassword = null;
    		public System.Web.UI.WebControls.Button cmdLogon = null;
    		public System.Web.UI.WebControls.RequiredFieldValidator reqUsername = null;
    		public System.Web.UI.WebControls.RegularExpressionValidator revPassword = null;
    
    		[Bindable(true),Category("TextBoxContents")]
    		public string Username
    		{
    			get
    			{
    				if (ViewState[_usernameStateKey] != null)
    					return (string)ViewState[_usernameStateKey];
    				else
    					return _username;
    			}
    			set
    			{
    				_username = value;
    				ViewState.Add(_usernameStateKey,value);
    			}
    		}
    		public string Password
    		{
    			get
    			{
    				if (ViewState[_passwordStateKey] != null)
    					return (string)ViewState[_passwordStateKey];
    				else
    					return _password;
    			}
    			set
    			{
    				_password = value;
    				ViewState.Add(_passwordStateKey, value);
    			}
    		}
    
    		public new void PreRender()
    		{
    			EnsureChildControls();
    			txtusername.Text = ViewState[_usernameStateKey] == null ? _username : (string) ViewState[_usernameStateKey];
    			txtpassword.Text = ViewState[_passwordStateKey] == null ? _password : (string) ViewState[_passwordStateKey];
    		}
    
    		protected override void CreateChildControls()
    		{
    			txtusername = new TextBox();
    			txtpassword = new TextBox();
    			cmdLogon = new Button();
    			reqUsername = new RequiredFieldValidator();
    			revPassword = new RegularExpressionValidator();
    			txtusername.ID = "txtusername";
    			
    			txtpassword.TextMode = TextBoxMode.Password;
    			cmdLogon.Text = "Logon";
    			txtusername.Width = 140;
    			txtpassword.Width = 140;
    			txtusername.MaxLength = 15;
    			txtpassword.MaxLength = 15;
    			txtpassword.TextMode = TextBoxMode.Password;
    			txtpassword.ID = "txtpassword";
    
    			cmdLogon.Text = "Logon";
    			cmdLogon.Attributes.Add("OnServerClick","Submit_Click");
    			
    			reqUsername.Display = ValidatorDisplay.Dynamic;
    			reqUsername.EnableClientScript = true;
    			reqUsername.ErrorMessage = "Username must not be blank";
    			reqUsername.ControlToValidate = "txtusername";
    
    			revPassword.Display = ValidatorDisplay.Dynamic;
    			revPassword.EnableClientScript = true;
    			revPassword.ErrorMessage = "Password must be at least 6 alpha-numeric charactors";
    			revPassword.ControlToValidate = "txtpassword";
    			
    			this.Controls.Add(txtusername);
    			this.Controls.Add(txtpassword);
    			this.Controls.Add(reqUsername);
    			this.Controls.Add(revPassword);
    		}
    		
    		/// <summary>
    		/// Render this control to the output parameter specified.
    		/// </summary>
    		/// <param name="output"> The HTML writer to write out to </param>
    		protected override void Render(HtmlTextWriter output)
    		{
    			output.Write("<table border=\"1\" width=\"300\" id=\"table1\">");
    			output.Write("<tr border=\"0\">");
    			output.Write("<td border=\"0\">Username:</td>");
    			output.Write("<td border=\"0\">");
    			txtusername.RenderControl(output);
    			output.Write("</td>");
                output.Write("</tr>");
    			output.Write("<tr border=\"0\">");
    			output.Write("<td border=\"0\">Password:</td>");
    			output.Write("<td border=\"0\">");
    			txtpassword.RenderControl(output);
    			output.Write("</td>");
    			output.Write("</tr>");
    			output.Write("<tr border=\"0\"><td colspan=\"2\"><div align=\"centre\">");
    			cmdLogon.RenderControl(output);
    			output.Write("<br>");
    			reqUsername.RenderControl(output);
    			output.Write("<br>");
    			revPassword.RenderControl(output);
    			output.Write("</div></td></tr>");
    			output.Write("</table>");
    		}
    	}
    
    	public class LoginControlDesigner : System.Web.UI.Design.ControlDesigner
    	{
    		public override string GetDesignTimeHtml() 
    		{
    			// Component is the control instance, defined in the base
    			// designer
    			LoginControl ctl = (LoginControl) Component;
    
    			
    			StringWriter sw = new StringWriter();
    			HtmlTextWriter output = new HtmlTextWriter(sw);
    
    			output.Write("<table border=\"1\" width=\"300\" id=\"table1\">");
    			output.Write("<tr border=\"0\">");
    			output.Write("<td border=\"0\">Username:</td>");
    			output.Write("<td border=\"0\">");
    			//ctl.txtusername.RenderControl(output);
    			output.Write("txtUsername");
    
    			output.Write("</td>");
    			output.Write("</tr>");
    			output.Write("<tr border=\"0\">");
    			output.Write("<td border=\"0\">Password:</td>");
    			output.Write("<td border=\"0\">");
    			//ctl.txtpassword.RenderControl(output);
    			output.Write("txtPassword");
    
    			output.Write("</td>");
    			output.Write("</tr>");
    			output.Write("<tr border=\"0\"><td colspan=\"2\"><div align=\"centre\">");
    			//ctl.cmdLogon.RenderControl(output);
    			output.Write("cmdLogin");
    
    			output.Write("<br>");
    			//ctl.reqUsername.RenderControl(output);
    			output.Write("<br>");
    			//ctl.revPassword.RenderControl(output);
    			output.Write("</div></td></tr>");
    			output.Write("</table>");
    
    			return sw.ToString();
    		}
    	}
    }
    Quotes:
    "I am getting better then you guys.." NoteMe, on his leet english skills.
    "And I am going to meat her again later on tonight." NoteMe
    "I think you should change your name to QuoteMe" Shaggy Hiker, regarding NoteMe
    "my sweet lord jesus. I've decided never to have breast implants" Tom Gibbons
    Have I helped you? Please Rate my posts.


  6. #6
    I wonder how many charact
    Join Date
    Feb 2001
    Location
    Savage, MN, USA
    Posts
    3,704

    Re: Custom control Properties

    Sorry, its INamingContainer.
    Code:
    public class LoginControl : System.Web.UI.WebControls.WebControl, INamingContainer
    As far as the Designer...
    see this:
    http://www.error-bank.com/microsoft....bl_Thread.aspx

    http://www.google.com/search?q=GetDe...&start=10&sa=N

  7. #7

    Thread Starter
    Not NoteMe SLH's Avatar
    Join Date
    Mar 2002
    Location
    192.168.0.1 Preferred Animal: Penguin Reason for errors: Line#38
    Posts
    3,051

    Re: Custom control Properties

    Thanks a lot for your continued help.

    I've now got the following code, which i think is the c# equivilent of the vb.net stuff in that link you gave. I still get the same result - the control isn't there at design time.

    BTW. i'm using MS ASP.NET Web Matrix, not Visual Studio as the designer, would this make a difference?

    Code:
    public class LoginControlDesigner : System.Web.UI.Design.ControlDesigner
    	{
    		protected override string GetEmptyDesignTimeHtml()
    		{
    			string HTML = "This is the No.1 Invisible control";
    			return CreatePlaceHolderDesignTimeHtml(HTML);
    		}
    		protected override string GetErrorDesignTimeHtml(Exception e)
    		{
    			return CreatePlaceHolderDesignTimeHtml(e.Message + "<br>Check to make sure all properties are valid.");
    		}
    		public override string GetDesignTimeHtml() 
    		{
    			// Component is the control instance, defined in the base
    			// designer
    			LoginControl ctl = (LoginControl) Component;
    			return GetEmptyDesignTimeHtml();
    		}
    	}
    Quotes:
    "I am getting better then you guys.." NoteMe, on his leet english skills.
    "And I am going to meat her again later on tonight." NoteMe
    "I think you should change your name to QuoteMe" Shaggy Hiker, regarding NoteMe
    "my sweet lord jesus. I've decided never to have breast implants" Tom Gibbons
    Have I helped you? Please Rate my posts.


Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width