views:

559

answers:

4

Ok time to show my complete lack of knowladge for all things web forms but here goes. I am extending the Panel control and OnPreRender sticking some additional controls inside of it (lets just say 1 textbox for simplicity). From here I am just letting the Panels Render method do its thing.

The issue I am having is that obviously every time this control is rerendered it is just sticks that same TextBox in the panel again with the value I am coding in the OnPreRender method. Now I dont actually want to repopulate the panel every time,

I want to stick the textbox contorl in there on first load and have them reloaded from the control/viewstate caches. In this case with my example of just sticking a single textbox in the panel, if the value of the textbox changes and a postback occurs I want that value to to remain the changed value.

Really basic webforms stuff I know, but I have never had to create custom controls in my time. ANy help appreciated.

Chris.

A: 

Inside your code you will need to manage the restore of viewstate information should you need the services of viewstate.

A good example here is this View State example by Microsoft. There are a few other items referenced in the code sample, but it should get you along the right path.

Mitchel Sellers
+1  A: 

Dynamic controls in ASP.NET are tricky, especially if you are new to webforms and the page lifecycle. If you can avoid dynamic controls, do so. Use controlName.Visible=false, and other tricks instead.

If you must then read this article. Rule of thumb,add controls early in the page life cycle, reference them later in the page lifecycle. PreRender is almost the very end, an uncommon place to be adding and using controls.

MatthewMartin
+2  A: 

You need to (re)create the child control (the textbox) in OnInit - so that it's there when LoadViewState and ProcessPostBackData is called.

See the server control lifecycle for more info.

Mark Brackett
Cheers, This is correct.
Owen
If you're using web forms, RUN DO NOT WALK and read about lifecycles in ASP.NET. Will save you mucho heartache.
Will
A: 

Not sure if this applies to all versions of .Net, (I think 2.0 or later) but there is a method called CreateChildControls that isn't really a part of the lifecycle exactly, it's basically called anytime the EnsureChildControls method is called. By default it is called before PreRender if it's not a postback. So basically your code would look like this:

public class SomeControl : WebControl, INamingContainer
{
  private TextBox someTextBox;

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

    someTextBox= new TextBox();
    someTextBox.ID = "tbxMain";

    Controls.Add(textboxToCheck);
  }
}

Now the part to not is that unless you call EnsureChildControls, you can't be 100% sure that the controls exist before the Public Properties on your control are filled by the ViewState load. What does this mean? Well take the code from before and add a property for the CssClass:

public class SomeControl : WebControl, INamingContainer
{
  private TextBox someTextBox;

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

    someTextBox= new TextBox();
    someTextBox.ID = "tbxMain";

    Controls.Add(textboxToCheck);
  }

  public String CssClass { get; set; }
}

In CreateChildControls you won't want this:

someTextBox.CssClass = CssClass;

Since there is no way to be sure the control exists yet. There's a couple ways you can handle this:

public String CssClass { get { EnsureChildControls(); return someTextbox.CssClass; }

 set
 { 
   EnsureChildControls();
   someTextbox.CssClass = value;
 }

In this example I am calling EnsureChildControls (Assuming you are setting the CssValue on the textbox in the CreateChildControls method) and setting or getting from the textbox.

Another way is putting anything that depends on the control's public properties in the OnPreRender method:

protected override void OnPreRender(EventArgs e)
{
  someTextbox.CssClass = CssClass;
}

Thus avoiding the mess of worrying about the property being filled already during the ViewState load.

One Note:

The use of INamingContainer can be important. Basically all that does is makes sure the controls on the parent control have an id that is unique on the page by applying the parent's name (And maybe more) to the id. Basically if the parent ID is Parent and the child control ID is Child the ID might show up as Parent_Child. This will solve problems with ViewState not populating the properties correctly or not at all.

Programmin Tool