Wednesday, May 7, 2008

CollapsiblePanelExtender and postback in C#

After a week of searching I found the solution to save the state of an Ajax collapsiblePanelExtender.
I want to show you that it is very easy to save the state after a postback.

Clientside

First you need to create your collapsiblePanelExtender:


TargetControlID="PanelNewsItems"
CollapsedSize="0"
ExpandedSize="220"
Collapsed="False"
ExpandControlID="LinkButtonPanelHeader"
CollapseControlID="LinkButtonPanelHeader"
ScrollContents="False"
TextLabelID="LinkButtonPanelHeader"
CollapsedText="Toon Nieuws"
ExpandedText="Verberg Nieuws"
ExpandDirection="Vertical"
ImageControlID="ImageCollapsePanel"
CollapsedImage="~/images/expand.gif"
ExpandedImage="~/images/collapse.gif"
SuppressPostBack="false"/>

Important is the SuppressPostback parameter. If you set it 'true' the postback will not be fired. So to create a postback the SuppresPostBack parameter needs to be set to 'false'.
The expandControl and the CollapseControl is in my case a LinkButton.




As you can see the LinkButton has an OnClientClick. This click calls a javascript function that saves the state of the collapsiblePanelExtender into a HiddenField.

So you have to put a HiddenField somewhere on your page:




Somewhere in the code you need to place the javascript code to set the hiddenfield value after the clientclick on the linkbutton:


function changeStateNews(){
objExtender = $find("<%=CollapsiblePanelExtenderNewsItems.ClientID%>");
objHiddenField = document.getElementById("<%=HiddenFieldNews.ClientID%>");
if(objExtender.get_Collapsed()){
objHiddenField.value = '0';
}
else objHiddenField.value = '1';
}

Serverside
That's it for the clientside. Now I'll show you the serverside code:


#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required by the ASP.NET Web Form Designer.
//
InitializeComponent();
base.OnInit(e);
}

///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///

private void InitializeComponent()
{
this.LinkButtonPanelHeader.Command += new CommandEventHandler(LinkButtonPanelHeader_Command);
this.RepeaterNewsItems.ItemDataBound += new RepeaterItemEventHandler(RepeaterNewsItems_ItemDataBound);
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion

void LinkButtonPanelHeader_Command(object sender, CommandEventArgs e)
{
if (HiddenFieldNews.Value == "1")
{
controlPanelExtender(true);
}
else
{
controlPanelExtender(false);
}

lib.cookie.setCookieValue(CookieName, HiddenFieldNews.Value);
}

void controlPanelExtender(bool value)
{
CollapsiblePanelExtenderNewsItems.Collapsed = value;
CollapsiblePanelExtenderNewsItems.ClientState = value.ToString().ToLower();
}

First to get the postback of the LinkButton you need to create the Command event in the InitializeComponent function.

In the Command function you can read the value of the HiddenField. According to the Hiddenfield value you can set the collapsed and the clientState of the collapsiblePanelExtender.

I also created an option in the Command function to save the state into a cookie. So the next time you open the page it sets the last saved state in the Page_Load function.

There is still one buggy thing I want to solve. If the server is very quick (say localhost) the postback sets the new state faster than the clientside. In other words: if you clicked on an expanded panel while its collapsing, the postback sets its state to collapsed, so it will collapse immediatly. My goal is to fire the postback after the clientside has finished the animation.

Any questions or reactions are welcome.