I recently came across the problem having an Accordion control on my site and wanted to load the pane content on demand to reduce loading time of the site. The Accordion was bound to a datasource and every pane should display data of another datasource. Databinding everything from the start led to an unacceptable load time of the page itself.
AFAIK there are two solutions for this problem. The first is also discussed in the AJAX Control Toolkit. You could define a static web method on your page and load the stuff you want asynchronously. I decided for a quick and dirty method by loading the pane content only if the use expands a specific pane and only the data for the specific pane is loaded.
I have the following tables in my application:
First of all I have this table filled with people. The Accordion control will be bound to this data so we have a pane for each person.
I also have a table with data related to the people above. This looks as follows:
There is a foreign key named PeopleId. While this sample builds on this table relation you can easily change it to fit your needs.
Now let’s add the datasource and the Accordion control to the site:
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:ConnectionString %>" SelectCommand="SELECT * FROM [People] ORDER BY [Lastname]"></asp:SqlDataSource> <ajaxToolkit:Accordion ID="Accordion1" DataSourceID="SqlDataSource1" HeaderCssClass="accordionHeader" HeaderSelectedCssClass="accordionHeaderSelected" ContentCssClass="accordionContent" FadeTransitions="true" FramesPerSecond="40" TransitionDuration="250" AutoSize="None" RequireOpenedPane="false" SuppressHeaderPostbacks="false" runat="server"> <HeaderTemplate> </HeaderTemplate> <ContentTemplate> </ContentTemplate> </ajaxToolkit:Accordion>
As you can see we simply added a SqlDataSource control selecting all the people of our people table and added a Accordion control to display the people there. We have bound the Accordion control to the datasource and added the HeaderTemplate and the ContentTemplate.
Now we want to display the name of the person in the HeaderTemplate. We also want to load the data of the people data table into the specific pane when the user expands that pane.
First of all we have to insert a LinkButton to the HeaderTemplate. This is not best practice but it does its job great.
<HeaderTemplate> <asp:LinkButton ID="LinkButton1" CommandName="LoadData" Width="100%" runat="server"> <%# Eval("Lastname") %> </asp:LinkButton> </HeaderTemplate>
As you can see I gave the LinkButton a width of 100% to fill all the header template. I specified a command name just in case there are more commands so that we know how to handle this in code-behind. What we know have to do is to make use of the Accordion event OnItemCommand. Since we do a postback here we have to handle this event to load the data.
<ajaxToolkit:Accordion ID="Accordion1" DataSourceID="SqlDataSource1" HeaderCssClass="accordionHeader" HeaderSelectedCssClass="accordionHeaderSelected" ContentCssClass="accordionContent" FadeTransitions="true" FramesPerSecond="40" TransitionDuration="250" AutoSize="None" RequireOpenedPane="false" SuppressHeaderPostbacks="false" runat="server" onitemcommand="Accordion1_ItemCommand">
The event looks like the following in code-behind:
protected void Accordion1_ItemCommand(object sender, CommandEventArgs e) { }
Now before proceeding let’s prepare our content template with the stuff we need to load the data:
<ContentTemplate> <asp:HiddenField ID="HiddenFieldPeopleId" Value='<%# Eval("Id") %>' runat="server" /> <asp:SqlDataSource ID="SqlDataSource2" runat="server" ConnectionString="<%$ ConnectionStrings:ConnectionString %>" SelectCommand="SELECT [Id], [SampleNumber], [SampleData] FROM [PeopleData] WHERE ([PeopleId] = @PeopleId)"> <SelectParameters> <asp:ControlParameter ControlID="HiddenFieldPeopleId" Name="PeopleId" PropertyName="Value" Type="Int32" /> </SelectParameters> </asp:SqlDataSource> <asp:GridView ID="GridView1" AutoGenerateColumns="false" AllowPaging="true" AllowSorting="true" DataKeyNames="Id" runat="server"> <Columns> <asp:BoundField DataField="Id" HeaderText="Id" SortExpression="Id" /> <asp:BoundField DataField="SampleNumber" HeaderText="SampleNumber" SortExpression="SampleNumber" /> <asp:BoundField DataField="SampleData" HeaderText="SampleData" SortExpression="SampleData" /> </Columns> </asp:GridView> </ContentTemplate>
You will notice a HiddenField here which is bound to the Id of the people from the people table. Next we added a SqlDataSource control which selects all the person data. The select parameter refers to the hidden field so we only select the data of the person we want. The Gridview is not bound to this SqlDataSource control. I have left the DataSourceId property empty. This is important otherwise the data would be loaded on page load which we don’t want.
The most important part is in code behind in our Accordion ItemCommand event:
protected void Accordion1_ItemCommand(object sender, CommandEventArgs e) { if (e.CommandName == "LoadData") { if (Accordion1.SelectedIndex != -1) { AjaxControlToolkit.AccordionPane pane = Accordion1.Panes[Accordion1.SelectedIndex]; if (pane != null) { SqlDataSource ds = (SqlDataSource)pane.FindControl("SqlDataSource2"); GridView gv = (GridView)pane.FindControl("GridView1"); if (ds != null && gv != null) { gv.DataSource = ds; gv.DataBind(); } } } } }
As you can see when clicking on the LinkButton in the HeaderTemplate the Accordion ItemCommand is fired. We take the selected pane and bind the datasource manually. It’s important to to check for Accordion1.SelectedIndex because when closing a pane the SelectedIndex is always –1 which would cause an error on the site.
This is all. This small trick helped come across with my problem of heavy data loading. A more elegant way would be to make use of a static webmethod on the site and load the data asynchronously. I found this solution to be a fast and easy way to this. You can extent the sample with some UpdatePanels and some UpdateProgress to show the user that something is loading in case of heavy data loading.
Download the sample project and try out for yourself.
Download: AjaxAccordionSample
A simple Accordion http://asp.net-informations.com/ajax/ajax-accordion.htm Asp.net Ajax accordian sample
caron