Creating a Web Forms Page That Persists Values

Creating a Web Forms Page That Persists Values

To illustrate how to use ViewState to persist values between round-trips, let’s create a variation of the Calculator1 Web Forms page from earlier in this chapter. This variation will work a little bit more like a real calculator. Instead of two text boxes, it will have only one. You type in a value and then click an operator button. You then type the second (or third or fourth) number and click the operator button that you want to apply. The result is displayed in the text box, as shown in Figure 20-6.

Figure 20-6.
The sample Web Forms page Calculator2.

This scenario requires that you store a running total, which we’ll do by putting the total into ViewState. The page’s ViewState property is an instance of the StateBag class, which in turn is implemented as a Dictionary object that allows you to store values in key-item pairs. You can assign values directly to ViewState using syntax such as the following:

ViewState["mystring"] = "a string value";
ViewState["myint"] = 42;

When you get values back out, they’re typed as objects, so you need to cast them appropriately, as shown here:

string myvalue = (ViewState["mystring"]).ToString();
int i = int.Parse(ViewState["total"].ToString());
note

We could also store the running total in session state. For data this small, however, the extra space for storing ViewState information is insignificant, so we might as well not incur any server overhead by using session state.

When you enter the first number and click an operator button, you don’t want to calculate a total yet. Instead, you want to wait until the second (or third or fourth) number is entered. The page needs to maintain a flag indicating whether this is a new calculation; this flag is set to true until after you’ve entered the first number. You have to store this flag in ViewState also.

Storing a running total and a new calculation flag introduces a new requirement. The first time the page runs, there’s no running total to store, plus you have to initialize the flag. The Page_Load event is raised the first time the page runs as well as every time a button is clicked, so it’s not sufficient to simply put the initialization logic in that handler. The solution is to check a page property named IsPostBack, which is set to false the first time the page runs and to true any time the page is running in response to a postback event.

Creating the Calculator2 Web Forms Page

This page is slightly simpler than the Calculator1 example. To create the page, add a Web Forms page named Calculator2 to your Visual C# Web application. Add the controls from the following table, and set their properties as indicated.

Notice that the CommandName property is set for all four of the operator buttons. The CommandName property gives you a way to pass command-specific information to a handler. As you’ll see in the next section, we can create a single handler for all four buttons but still be able to tell easily which button was clicked.

Adding Code to the Calculator2 Web Forms Page

To add code to the Calculator2 page, open the code file for the page. (Right-click the page in Solution Explorer, and choose View Code from the shortcut menu.) Create two private member variables to hold the running total and the flag indicating whether this is a new calculation, as shown here:

private double StoredValue;
private bool NewCalculationFlag;

Now create the initialization logic in the Page_Load handler. If this is the first time the page is running (that is, if the page’s IsPostBack property is false), you need to initialize the two keys in the ViewState property to hold the running total and the flag. However, if the page is being posted back, you need to read the keys back out of the ViewState property and into the member variables, as shown here:

private void Page_Load(object sender, System.EventArgs e)
{
    if(this.IsPostBack)
    {
        StoredValue = double.Parse(ViewState["total"].ToString());
        NewCalculationFlag = 
            bool.Parse(ViewState["NewCalculationFlag"].ToString());
    }
    else
    {
        ViewState["total"] = 0;
        ViewState["NewCalculationFlag"] = true;
    }
}

When an operator button is clicked, the action that occurs depends on whether this is the first number in the calculation. If it is, all we need to do is store that number, our initial running total, because there’s nothing to calculate yet. But if it’s not the first number, we can do the calculation. The result is a new running total, which is displayed in the text box and is stored back into ViewState.

The logic for each button differs by only one line—the actual calculation—so it’s reasonable to use a single handler for all of them. Create a handler named Calculate for the AddButton control’s Command event (not the Click event). The Command event is similar to the Click event, except that it passes to the handler the value of the sender object’s CommandName property. Bind the Command event of the remaining buttons to this same event. Refer to the section “Creating the Event Handlers,” earlier in this chapter, for the procedure for creating a single handler for multiple buttons.

In the handler, check the NewCalculationFlag variable, and if it’s true, clear the flag and store both the flag and the number from the text box in ViewState. Otherwise, get the running value out of ViewState and perform the calculation with the new value in the text box. To determine which operator button was clicked, test the CommandName property of the CommandEventArgs object passed in the handler. In the code below, this is done with a switch statement.

private void Calculate(object sender, 
                       System.Web.UI.WebControls.CommandEventArgs e)
{
    if(NewCalculationFlag)
    {
        ViewState["NewCalculationFlag"] = false;
        ViewState["total"] = Number1TextBox.Text;
    }
    else
    {
        switch(e.CommandName)
        {
            case("Subtract"):
            {
                StoredValue -= double.Parse(Number1TextBox.Text);
                break;
            }
            case("Add"):
            {
                StoredValue += double.Parse(Number1TextBox.Text);
                break;
            }
            case("Multiply"):
            {
                StoredValue *= double.Parse(Number1TextBox.Text);
                break;
            }
            case("Divide"):
            {
                if((double.Parse(Number1TextBox.Text) != 0)) 
                    StoredValue /= double.Parse(Number1TextBox.Text);
                break;
            }
        }
        ViewState["total"] = StoredValue;
        Number1TextBox.Text = StoredValue.ToString();
    }
}

Finally create a handler for the Clear button that resets the ViewState values to their initial state and that clears the TextBox control, as shown here:

private void ClearButton_Click(object sender, System.EventArgs e)
{
    Number1TextBox.Text = "";
    ViewState["total"] = 0;
    ViewState["NewCalculationFlag"] = true;
}


Part III: Programming Windows Forms