Search code examples
c#asp.netviewstatepageload

c# How to utilize Page_init, ViewState and Page_Load properly?


I have been working with Web Forms for a short while now and I have read most of what I have found about this on google. However, I am still unclear on how to work with this properly. I like the picture in this answer, but find it a bit too generic. I have not found one decent, concrete example on how to work with these events.

I am currently creating several controls dynamically in code behind in the Page_Load event:

foreach (Service service in Services)
{
    // service div
    HtmlGenericControl serviceDiv = new HtmlGenericControl("div");
    serviceDiv.ID = service.ID;
    serviceDiv.Style.Add(HtmlTextWriterStyle.TextAlign, "center");
    outerDiv.Controls.Add(serviceDiv); //outerDiv exists in the aspx page

    // service updatepanel
    UpdatePanel uPanel = new UpdatePanel()
    {
        ID = service.ID + "_uPanel",
        UpdateMode = UpdatePanelUpdateMode.Conditional
    };
    serviceDiv.Controls.Add(uPanel);

    // status span
    HtmlGenericControl statusSpan = new HtmlGenericControl("span");
    statusSpan.ID = service.ID + "_statusSpan";
    statusSpan.InnerHtml = service.Status;
    uPanel.ContentTemplateContainer.Controls.Add(statusSpan);

    // show specific content
    if (service.Status.Equals(ServiceControllerStatus.Running.ToString()))
    {
        // status color
        statusSpan.Attributes.Add("class", "status-run");

        // stop button
        HtmlButton stopButton = new HtmlButton();
        stopButton.ID = service.ID + "_btnStop";
        stopButton.InnerHtml = "<i class=\"fa fa-stop btn-red\"/></i>";
        stopButton.Attributes.Add("type", "button");
        stopButton.Attributes.Add("runat", "server");
        stopButton.Attributes.Add("class", "btn btn-link btn-xs");
        stopButton.Attributes.Add("title", "Stop");
        stopButton.ServerClick += new EventHandler(BtnStop_Click);
        ScriptManager.GetCurrent(this).RegisterAsyncPostBackControl(stopButton);
        uPanel.ContentTemplateContainer.Controls.Add(stopButton);

        // restart button
        HtmlButton restartButton = new HtmlButton();
        restartButton.ID = service.ID + "_btnRestart";
        restartButton.InnerHtml = "<i class=\"fa fa-refresh btn-blue\"/></i>";
        restartButton.Attributes.Add("type", "button");
        restartButton.Attributes.Add("runat", "server");
        restartButton.Attributes.Add("class", "btn btn-link btn-xs");
        restartButton.Attributes.Add("title", "Restart");
        restartButton.ServerClick += new EventHandler(BtnRestart_Click);
        ScriptManager.GetCurrent(this).RegisterAsyncPostBackControl(restartButton);
        uPanel.ContentTemplateContainer.Controls.Add(restartButton);
    }
    else
    {
        // status color
        statusSpan.Attributes.Add("class", "status-stop");

        // start button
        HtmlButton startButton = new HtmlButton();
        startButton.ID = service.ID + "_btnStart";
        startButton.InnerHtml = "<i class=\"fa fa-play btn-green\"/></i>";
        startButton.Attributes.Add("type", "button");
        startButton.Attributes.Add("runat", "server");
        startButton.Attributes.Add("class", "btn btn-link btn-xs");
        startButton.Attributes.Add("title", "Start");
        startButton.ServerClick += new EventHandler(BtnStart_Click);
        ScriptManager.GetCurrent(this).RegisterAsyncPostBackControl(startButton);
        uPanel.ContentTemplateContainer.Controls.Add(startButton);
    }

    // version span
    HtmlGenericControl versionSpan = new HtmlGenericControl("span");
    versionSpan.ID = service.ID + "_version";
    versionSpan.InnerHtml = service.Version;
    versionSpan.Attributes.Add("class", "version-text");
    serviceDiv.Controls.Add(versionSpan);

What would I gain from creating these in Page_Init? If I create them in Page_Init, how do I access them in Page_Load? Private global lists of UpdatePanels and HtmlButtons feels so unclean.

I know that the ViewState loads between Page_Init and Page_Load, but what does that really mean? Since I don't do full postbacks, but instead use RegisterAsyncPostBackControl to only update the UpdatePanel's on postback, don't I need to re-populate in Page_Load?


Solution

  • If you don't need the ViewState, then you can also create the controls in Page_Load. The ViewState is used to store the values of the controls (which ones depends on the control) and to use them when the PostBack is sent to the server.

    For instance, if you have a textbox, the PostBack contains the new value of the textbox and also the old value in the ViewState. The ASP.NET framework now compares those two and raises the TextChanged event if necessary. Without ViewState, this would not be possible.

    The best advice you can give regarding dynamically created controls in ASP.NET WebForms is to avoid using them. They increase complexity very fast und are usually not necessary (even if it seems so at first).

    In the majority of the cases, there is a much simpler approach, e.g. by using a Repeater. In your case, you have a list of services. You can bind this list to a Repeater and by that avoid to create the controls manually. See this link on how to use a Repeater.

    Another upside of using a Repeater is that you can define the UI in the ASPX markup instead of in the code behind file. In your example, you change the UI based upon the status of the service. In this case, using the ItemDataBound-event of the Repeater might be a good option.