Tuesday, January 15, 2008

ViewState-backed Properties - Part One

Why use a ViewState-backed Property?

This is the first post in a multi-part series on using ViewState to back your Page Properties.  If you've done any kind of development with ASP.NET then you've probably had to use a ViewState-backed Property at some point.  Accessing and setting a Property is much easier than working with ViewState directly throughout your code, especially if the name of your Key may change.  There is one thing to consider, though.

Default Value for a ViewState-backed Property

It's generally good practice to check your ViewState-backed Property for null before trying to access it.  One thing worth noting is that you may want to display a default value if one hasn't been set.  The following code may look familiar:

   1: private string Standard
   2: {
   3:     get
   4:     {
   5:         if (ViewState["Standard"] != null)
   6:         {
   7:             return (string)ViewState["Standard"];
   8:         }
   9:         else
  10:         {
  11:             return "My default value";
  12:         }
  13:     }
  14:     set { ViewState["Standard"] = value; }
  15: }

Null Coalescing Operator

Lately there have been quite a few blog posts on using the null coalescing operator (??).  I won't go into detail here about its use except to say that it returns the first operand if it is not null and the second operand if the first is null.  When applied to ViewState-backed Properties the code can be shortened and, in my opinion, made more readable.  Consider the following code which essentially works the same as the previous example:

   1: private string MyDefaultValue 
   2: {
   3:     get { return (string)(ViewState["MyDefaultValue "] ?? "My default value"); }
   4:     set { ViewState["MyDefaultValue "] = value; }
   5: }

If ViewState["MyDefaultValue"] is null then the string "My default value" is returned.  If it is not null then the value it holds is cast to a string and returned.  In the past, developers have argued that the null coalescing operator makes code more difficult to read.  With all the attention it's gotten lately, I no longer think that's a valid argument.  In fact, I'll be using it throughout this series on ViewState-backed Properties.

Working Example

Below I've included a working page demonstrating what will be returned before and after the ViewState-backed Property is set.  Enjoy!

   1: <%@ Page Language="C#" AutoEventWireup="false" CodeFile="DefaultValue.aspx.cs" Inherits="DefaultValue" %>
   2: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
   3:  
   4: <html xmlns="http://www.w3.org/1999/xhtml" >
   5:     <head runat="server">
   6:         <title>Default Value</title>
   7:     </head>
   8:     <body>
   9:         <form id="frmMain" runat="server">
  10:             <div>
  11:                 <p>
  12:                     When this button is clicked, a default value will be displayed even though the ViewState-backed property has not been set.
  13:                 </p>
  14:                 <asp:Label ID="lblDefaultValue" runat="server" Text="The value is:  " />
  15:                 <br />
  16:                 <asp:Button ID="btnDefaultValue" runat="server" Text="Load Default" OnClick="btnDefaultValue_Click" />
  17:             </div>
  18:             <div>
  19:                 <p>
  20:                     When this button is clicked, the ViewState-backed property will be set and then displayed.
  21:                 </p>
  22:                 <asp:Label ID="lblSetValue" runat="server" Text="The value is:  " />
  23:                 <br />
  24:                 <asp:Button ID="btnSetValue" runat="server" Text="Set Value" OnClick="btnSetValue_Click" />
  25:             </div>
  26:             <p>
  27:                 Clicking the first button again will now display the new set value as well.
  28:             </p>
  29:         </form>
  30:     </body>
  31: </html>
   1: using System;
   2: using System.Data;
   3: using System.Configuration;
   4: using System.Collections;
   5: using System.Web;
   6: using System.Web.Security;
   7: using System.Web.UI;
   8: using System.Web.UI.WebControls;
   9: using System.Web.UI.WebControls.WebParts;
  10: using System.Web.UI.HtmlControls;
  11:  
  12: public partial class DefaultValue : System.Web.UI.Page
  13: {
  14:     public DefaultValue() { Load += new EventHandler(Page_Load); }
  15:  
  16:     protected void Page_Load(object sender, EventArgs e) { }
  17:  
  18:     protected void btnDefaultValue_Click(object sender, EventArgs e)
  19:     {
  20:         lblDefaultValue.Text = "The value is:  " + MyDefaultValue;
  21:     }
  22:  
  23:     protected void btnSetValue_Click(object sender, EventArgs e)
  24:     {
  25:         MyDefaultValue = "My set value";
  26:         lblSetValue.Text = "The value is:  " + MyDefaultValue ;
  27:     }
  28:  
  29:     private string MyDefaultValue 
  30:     {
  31:         get { return (string)(ViewState["MyDefaultValue "] ?? "My default value"); }
  32:         set { ViewState["MyDefaultValue "] = value; }
  33:     }
  34:  
  35:     private string Standard
  36:     {
  37:         get
  38:         {
  39:             if (ViewState["Standard"] != null)
  40:             {
  41:                 return (string)ViewState["Standard"];
  42:             }
  43:             else
  44:             {
  45:                 return "My default value";
  46:             }
  47:         }
  48:         set { ViewState["Standard"] = value; }
  49:     }
  50: }

1 comment:

Rey said...

Howdy.
Came across your post while Googling how to retrieve from multiple pages.
Nice work and easy to understand as examples on how to return values from multiple pages was not even mentioned on MS pages.

While I do get values returned, the called page now appears as a modal version of the calling page.
Have you encountered this in your testing? Called page was via attributes.add("onclick",
"javascript:window.showModalDialog('frmAlternateAddress.aspx', null, 'center:yes;status:no;dialogWidth:370px; dialogHeight:350px;dialogHide:true;help:no;scroll:no');");

Thanks for any light you can shed on this issue.