| 
                    
                        | How to Really write a Server Control in ASP.Net
    - November 13, 2013 Find Missing Dependency DLLs on Win 7
    - March 5, 2012 Nullable TryParse 
    - May 26, 2011 Diff SQL Server Stored Procedures, November 15, 2010 Reporting Services Extranet Access, March 16, 2010 Case of the missing WaitCursor, January 7, 2009 Simple Submit Button Disable, December 9, 2009 An Efficient Memory Stream, September 29, 2009 Approach Plate Download - May 14, 2009 WPF Binding - Async Web Services - April 10, 2009 Developing the Blog 
    - April 4, 2009 |  | 
Okay, it has been a long time since last blogging here.  But, alas, that is not why you are here, so I will spare you the stories of 
    cross country trips, and Red Sox 
championships...
 
    So, I have a client who needed a clean interface for his website, and I worked 
    with a colleague on a new design. At first, we used a trial license of the 
    Componant Art Grid to do all our grids.  But, sorry, that grid is too 
    awkward to work with.  After searching about, I came across jqGrid. I have to admit, Tony Tomov did an incredible 
    job writing this library, and Oleg has done a huge job supporting it on Stack Overflow. 
    The guy is a machine. 
        Anyway.  I began loving jqGrid the second I started working with it.  
        They thought of everything when writing it.  The only thing missing was 
        that I had to write everything in Javascript, and I am working in ASP.Net, so 
        there was no way to consistently control the JS from the code behind.  The 
        makers of jqGrid offer an ASP.Net control to do this, but, being a programmer myself, 
        I thought it was about time I bit off writing a Server Conrtol myself. 
        So, the first thing you do to write a Server Control in ASP.Net, is Google 
        ASP.Net Server Control.  Good luck with that.  The main articles are: 
        Developing Custom ASP.NET Server Controls and, when you really want to get 
        down and dirty, Custom Property State Management Example.  
        You basically start off leaning about how a control works, and how the postback 
        state works. 
        Now, if you don't know how ViewState works on an ASP.Net page, then you need to 
        brush up on that (I won't put a link here, as it will most likey go stale, but 
        just google "asp.net view state", and start reading).  But the examples 
        given on the MS sites will lead you into writing a lot of code, and, eventually, 
        set you up for a costly rewrite. 
        For starters, let's look at their idea of property setters in a WebControl:         public virtual BookType BookType
        {
            get
            {
                object t = ViewState["BookType"];
                return (t == null) ? BookType.NotDefined : (BookType)t;
            }
            set
            {
                ViewState["BookType"] = value;
            }
        }
        Ok, you want to write this for every property in your class?  Wouldn't it 
        be easier to write the following, instead? 
        
                
        public int? 
        Height{
 get { return 
        GetProp<int?>("Height"); 
        }
 set { SetProp(value,
        "Height"); }
 }
 
        (And better yet, if you use .Net 4.5, and add a little code on the library, you can 
        just write: 
        
                
        public int? 
        Height{
 get { return 
        GetProp<int?>(); 
        }
 set { SetProp(value); }
 }
 
        but we'll get to that later). 
        The next problem with the examples has to do with tags nested within your server 
        control's tags.  Take, for example, a common construct.  Like a 
        collection of items within your control.  You have the base control, which 
        is happy to collect viewstate for all the tag's attributes for you using the 
        above construct.  But the examples for nested tags are nuts.  Look at 
        how you are expected to save and load viewstate for contained (nested) tags:         protected override void LoadViewState(object savedState)
        {
            Pair p = savedState as Pair;
            if (p != null)
            {
                base.LoadViewState(p.First);
                ((IStateManager)Author).LoadViewState(p.Second);
                return;
            }
            base.LoadViewState(savedState);
        }
        protected override object SaveViewState()
        {
            object baseState = base.SaveViewState();
            object thisState = null;
            if (authorValue != null)
            {
                thisState = ((IStateManager)authorValue).SaveViewState();
            }
            if (thisState != null)
            {
                return new Pair(baseState, thisState);
            }
            else
            {
                return baseState;
            }
        }
        This is from their "Custom Property State Management Example".  Note how 
        they have invented this very specific case where they use a "Pair" class to 
        store the control class's view state, and then add a "Second" item to the class 
        to hold the nested class's state.  This will work great if you only ever 
        have one nested class.  But what about 6 classes.  Or classes nesting 
        classes, and so on. 
        So, when I stared my jqGrid Server Control, I laid out the "schema" of the class 
        as follows: 
        
            
        <jq:Grid
        ID="GLMasterGrid"
        runat="server"
        ClientIDMode="Static"
        Caption="Current GL 
        Master Groups"SortColumn="SeqNum"
        PixelsFromBottom="440"
        OnSelectRow="edit">
 <Ajax WebMethod="GetGLMasterGrid" 
        EditMethod="AddGLMaster"
        />
 <Editor Width="400" />
 <Pager>
 <ExcelExport
        FileName="TripsWareGLMasterGroups"
        />
 </Pager>
 <Columns>
 <jq:Column
        PropertyName="CategoryGroupID"
        Visible="false"
        IsKey="true"
        ExcelIgnore="true"
        />
 <jq:Column
        ID="DescName"
        PropertyName="DescName"
        Title="GL Master Group"
        Width="225"
        Search="true"
        >
 <Edit
        Rules="required:true"
        Options="size:30, 
        maxlength:150" />
 </jq:Column>
 <jq:Column
        ID="GLGroupCode"
        PropertyName="GLGroupCode"
        Title="GL Master Group 
        Code" Width="225"
        Search="true"
        >
 <Edit
        Options="size:30, 
        maxlength:50" />
 </jq:Column>
 <jq:Column
        ID="SeqNum"
        PropertyName="SeqNum"
        Title="Display Seq"
        Width="90"
        Align="Right">
 <Edit
        Rules="number:true,minvalue:0"
        Options="maxlength:8,width:40"
        />
 </jq:Column>
 <jq:Column
        ID="DeleteTemplate"
        FormatterTemplate="DeleteTemplate"
        Width="80"
        Align="Center"
        Sortable="false"
        />
 </Columns>
 </jq:Grid>
 
        This is just an example, but demonstrates what I wanted to accomplish.  
        With the above tags, I was able to easily emit the jqGrid JavaScript that could 
        drive a grid for my client.  There were properties to set the width of the 
        grid, and to drive the pager and editor, and specify the ajax calls to make.  
        Actually, the first cut at writing it went very fast, since I only handled 
        loading the control, and didn't deal with view state.  That is kind of the 
        first dirtly little secret of server controls: If you are going to write an Ajax 
        control that doesn't care about postbacks, then, heck, you can just write a POCO 
        class and your're done.  And that is what I had for my client for a few 
        months.  When I did need to deal with changes to the underlying class on 
        postback, I just set the values again. 
        But to do it right, and really right, I was going to have to deal with the 
        nested viewstate problem. 
        So I broke the problem into 2 parts: 
        A typical WebControl comes raring to go with it's own ViewState object.  
        This object can serialize common types into the viewstate hidden field (int, 
        string, and even arrays).  But don't try to store a complex type in there. 
        Like the MS example above, you need to develop some kind of trick to store and 
        load their viewstate.  Instead of storing my nested tag and its atributes 
        in a Second parameter in a Pair class (or a third in a Triplet, and so on), I 
        just derived my nested tag's class from a new, IStateManager, class, called 
        StateManager.  This class has the exact same behavior as a WebControl 
        class, in that it has a contained ViewState StateBag where it can store its 
        attributes, and deals with Save and Load (and IsTracking).  Furthermore, I 
        introduced a new "object store" which sits next to the WebContol and 
        StateManager's ViewState which stores these nested objects, and can call on them 
        to Save and Load, since the nested objects stored in this dictionary are 
        IStateManager classes. 
        Next, I created a common class (StateManagerViewState) to store either 
        WebControl's ViewState, or a new StateBag for the the StateManager class, as 
        well as any nested objects, and whenever the control or one of its nested 
        controls sets a property, it trickles down to this contained class.  A call 
        to SaveViewState or LoadViewState to either the WebControl or StateManager 
        object will correctly save and load all the properties as well as nested 
        objects.  So, on postback, we get all the properties set for all the nested 
        objects 
        Finally, I implemented a StateManagerCollection<T> class, borrowing from the 
        MS StateManagedCollection class, but only collecting my new, StateManager 
        classes, and I piggy backed on the StateManager class to create a Dictionary 
        class, StateManagedDictionary<T>, which just stores values of type T in the 
        StateManager's base class's ViewState. 
        So, how does it all work?  Well, all properties, whether they are in the 
        control or nested, simply have to be set by calling SetProp<T>(value, 
        "propName").  A nested object is set or retrieved with the 
        SetNestedProp<StateManager>(value, "propName") call, where the nested class must 
        be derived from StateManager. 
        
            
        public class
        Grid : 
        StateManagerWebControl{
 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
 [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
 public
        Pager Pager { get 
        { return GetNestedProp<Pager>("Pager"); 
        } }
 
 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
 [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
 public
        Ajax Ajax { get 
        { return GetNestedProp<Ajax>("Ajax"); 
        } }
 
 [Bindable(true), Category("Appearance"), 
        DefaultValue(""),
        Localizable(true)]
 public
        new string Width
 {
 get { return 
        GetProp<string>("Width"); 
        }
 set { SetProp(value,
        "Width"); }
 }
 
 [Bindable(true), Category("Appearance"), 
        DefaultValue(""),
        Localizable(true)]
 public
        new string 
        Height
 {
 get { return 
        GetProp<string>("Height"); 
        }
 set { SetProp(value,
        "Height"); }
 }
 
 
        and so on.  Note how the class does not have to be cognizant of View State.  
        It is just getting and setting the property values by name.  The base 
        classes take care of holding on to the view state, or nested classes and their 
        view states, and tracking and Save/Load.  And, for example, the Ajax class 
        that is nested in this WebControl, above, is simply: 
        
            
        public class
        Ajax : 
        StateManager{
 public
        string WebMethod
 {
 get { return 
        GetProp<string>("WebMethod"); 
        }
 set { SetProp(value,
        "WebMethod"); }
 }
 
 public
        string EditMethod
 {
 get { return 
        GetProp<string>("EditMethod"); 
        }
 set { SetProp(value,
        "EditMethod"); }
 }
 
        and so on.  And, with the CallerMemberName attribute added to .Net 4.5, 
        we can just add a small change to the SetProp and GetProp functions to trim off 
        the "get_" and "set_" of the properties, and we can dispense with the 
        "propertyName" parameters altogether.  At that point, everything would be 
        compiler checked! 
        
           
        public class
        Ajax : 
        StateManager{
 public
        string WebMethod
 {
 get { return 
        GetProp<string>(); 
        }
 set { SetProp(value); }
 }
 
 public
        string EditMethod
 {
 get { return 
        GetProp<string>(); 
        }
 set { SetProp(value); }
 }
 
        Lastly, there is the code to support a collection: 
             
        public class 
        Column : StateManager{
 public
        bool? IsKey
 {
 get { return 
        GetProp<bool?>("IsKey"); 
        }
 set { SetProp(value,
        "IsKey"); }
 }
 public
        bool? Visible
 {
 get { return 
        GetProp<bool?>("Visible"); 
        }
 set { SetProp(value,
        "Visible"); }
 }
 etc
 
        and the collection which holds it: 
        
            
        public class
        JqColumnCollection :
        StateManagerCollection<Column>{
 public
        void RenderContents(string 
        tableID, HtmlTextWriter output)
 {
 output.WriteLine("var colModel = [");
 output.Indent++;
 string comma = " ";  // first 
        line has no prepended comma
 foreach (Column 
        column in this)
 {
 output.Write(comma);
 column.RenderContents(tableID, output);
 comma = ","; // now start prepending commas here on 
        out
 }
 output.Indent--;
 output.WriteLine("];");
 }|
 
        and so on. 
        Here is the link to the code: StateManager.cs  I doubt anyone will just 
        try and dump it in their code, but the essence is there.  Feel free to 
        email me with questions, and I will try and answer you. 
        Hopefully this is a cleaner way to start your Server Control.  I know now 
        that I have writen this, I will not shy away from writing them, as now I can 
        focus on the control and the HTML it emits, as opposed to worrying about whether 
        I have saved state correctly. |