Saving the Telerik RadSplitter/RadPane State

Telerik makes UI controls for ASP.NET (and they are getting in Windows Forms controls too apparently) and they’ve done a great job.   But, everything has it’s little quirks.  I was working with the RadSplitter, a control that allows you to make collapsable / resizable panels on your webpage, when I ran across a little problem: persisting the state to a cookie.

The cool thing about the RadSplitter is that you can resize / collapse a pane on the Client-Side, and the control will use JavaScript to update hidden fields on the page so it sends the new size and collapse state back to the server.  We wanted to store that state in a cookie so when users closed the browser and returned, the resizable sections would retain their last size and collapse state.

Here’s the issue:  let’s say you have a pane that, by default, is 200px wide.  You resize that pane on the client side to 350px, then collapse it (hide it).  When you post the page back to the server, the pane reports its width as 0px.  So, how do you save the width of an updated pane when it’s in a collapsed state?

The answer lies in the ExpandedWidth property, which is an internal value to the control that is not publicly exposed.  When a pane is collapsed, the ExpandedWidth property holds the width to which the pane should expand when expanded.  ExpandedWidht is 0px when the pane is fully expanded.

So, how do you get this value?  All of the state information about a RadPane comes back in as a JavaScript Object Notation (JSON) string in a hidden field, which we can intercept and parse to acquire the ExpandedWidth property (or whatever other property you want to find).  Here’s the code to save and load pane state for a RadPane in a RadSplitter:

/// <summary>
/// Regular expression used to parse JSON object info comming back from the Telerik splitter control. Telerik did not expose
/// the expandedWidth property (which stores the width of the pane when it is collapsed) so you have to acquire it using a workaround
/// </summary>
private static Regex SplitterRegex = new System.Text.RegularExpressions.Regex(“(?:”collapsed”:(?<collapsed>[^,\}]*))(?:.*)(?:”expandedSize”:(?<expandedSize>[^,\}]*))”, RegexOptions.IgnoreCase);

/// <summary>
/// Saves splitter settings to the setting cookie
/// </summary>
private void SaveSplitterSettings()
{
    if (splitter != null)
    {
        string splitterStateString = Page.Request.Form[paneLeft.ClientID];
        if(!string.IsNullOrEmpty(splitterStateString))
        {
            Match match = SplitterRegex.Match(splitterStateString);
            if (match.Success)
            {
                try
                {
                    bool collapsed = bool.Parse(match.Groups[1].Value);
                    string width;
                    if (collapsed)
                    {
                        width = match.Groups[2].Value + “px”;
                    }
                    else
                    {
                        width = paneLeft.Width.ToString();
                    }
                    HttpCookie settingCookie = new HttpCookie(“iswSplitterSettings”);
                    settingCookie.Values.Add(“LW”, width);
                    settingCookie.Values.Add(“LS”, collapsed ? “1” : “0”);
                    Page.Response.Cookies.Add(settingCookie);
                }
                catch
                {
                    //Do nothing
                }
            }
        }
    }
}

/// <summary>
/// Loads splitter settings from the setting cookie
/// </summary>
private void LoadSplitterSettings()
{
    HttpCookie settingCookie = Page.Request.Cookies[“iswSplitterSettings”];
    if (settingCookie != null)
    {
        try
        {
            paneLeft.Width = new Unit(settingCookie.Values[“LW”].ToString());
            paneLeft.InitiallyCollapsed = (bool)(settingCookie.Values[“LS”] == “1”);
        }
        catch
        {
            //Do nothing – allow the control to sort itself out
        }
    }
}