Ajax.Net Example: Using an UpdatePanelAnimationExtender to place an animated gif over a GridView
I recently was working on an Asp.Net project that contained quite a few search pages. These pages all followed a similar structured pattern where the user had a set of fields they could filter on by typing in values and pressing the search button. The results were displayed in a GridView where the user could sort by clicking on column headers, export the results to excel, etc... To help improve user experience, we placed each of the GridViews in an asp UpdatePanel so while the user refined the search (sorting, adding or removing additional filters), only the GridView would be refreshed and not the entire page. Additionally, we wanted to add a few standard UI cues (disabling the Search button, fading out the GridView, and placing a progress indicator over the GridView) letting the user know an operation was currently in progress.
Download Code | View live demo
It turned out that adding these UI cues was pretty easy with the help of the UpdatePanelAnimationExtender. Applying the first 2 cues (disabling the Search button and fading out the GridView) were really simple since there were already a couple of Animation Actions already defined specifically for these tasks. Placing the animated gif in the center of the GridView was only slightly more difficult. After the wrapping the GridView inside the UpdatePanel and defining the Search button as the trigger, I added the markup for the UpdateProgressAnimationExtender, specify which animations I would like and when they should run. As you can see in the code snippet below, I am telling the extender control to run the ScriptAction, EnableAction and FadeOut actions both OnUpdating (when the panel starts the async-postback) and OnUpdated (when the panel has been refreshed). When OnUpdating runs, the onUpdating javascript function is invoked centering the animated gif over the GridView, the btnSearch asp:Button is disabled, and the contents of the UpdatePanel are faded-out. OnUpdated fires the animations that are responsible for reversing these actions - the btnSearch button is re-enabled, the UpdatePanel is faded back in, and the onUpdated javascript function is invoked removing the animated gif.
<asp:UpdatePanel ID="updatePanel" runat="server"> <Triggers> <asp:AsyncPostBackTrigger ControlID="btnSearch" EventName="Click" /> </Triggers> <ContentTemplate> <asp:GridView ID="gvCustomers" runat="server" AllowPaging="true" AllowSorting="true" PageSize="20" DataSourceID="sqldsCustomers" Width="95%"> <AlternatingRowStyle BackColor="aliceBlue" /> <HeaderStyle HorizontalAlign="Left" /> </asp:GridView> </ContentTemplate> </asp:UpdatePanel> <ajaxToolkit:UpdatePanelAnimationExtender ID="upae" BehaviorID="animation" runat="server" TargetControlID="updatePanel"> <Animations> <OnUpdating> <Parallel duration="0"> <%-- place the update progress div over the gridview control --%> <ScriptAction Script="onUpdating();" /> <%-- disable the search button --%> <EnableAction AnimationTarget="btnSearch" Enabled="false" /> <%-- fade-out the GridView --%> <FadeOut minimumOpacity=".5" /> </Parallel> </OnUpdating> <OnUpdated> <Parallel duration="0"> <%-- fade back in the GridView --%> <FadeIn minimumOpacity=".5" /> <%-- re-enable the search button --%> <EnableAction AnimationTarget="btnSearch" Enabled="true" /> <%--find the update progress div and place it over the gridview control--%> <ScriptAction Script="onUpdated();" /> </Parallel> </OnUpdated> </Animations> </ajaxToolkit:UpdatePanelAnimationExtender> <div id="updateProgressDiv" style="display: none; height: 40px; width: 40px"> <img src="Img/dot-net-green.gif" /> </div>
Like I mentioned earlier, centering the animated gif was only slightly more work. To accomplish this I included a fixed width div tag containing the image and set its display style to none. Then when the OnUpdating animation fires the ScriptAction, I find the div, set the display back to visible, figure out the bounds of both the GridView and the progress div, and finally I do the math to determine when the div needs to be placed to overlay the GridView. The onUpdated function just sets the display style of the div back to none. Here are the functions ...
function onUpdating(){ // get the update progress div var updateProgressDiv = $get('updateProgressDiv'); // make it visible updateProgressDiv.style.display = ''; // get the gridview element var gridView = $get('<%= this.gvCustomers.ClientID %>'); // get the bounds of both the gridview and the progress div var gridViewBounds = Sys.UI.DomElement.getBounds(gridView); var updateProgressDivBounds = Sys.UI.DomElement.getBounds(updateProgressDiv); // do the math to figure out where to position the element (the center of the gridview) var x = gridViewBounds.x + Math.round(gridViewBounds.width / 2) - Math.round(updateProgressDivBounds.width / 2); var y = gridViewBounds.y + Math.round(gridViewBounds.height / 2) - Math.round(updateProgressDivBounds.height / 2); // set the progress element to this position Sys.UI.DomElement.setLocation (updateProgressDiv, x, y); } function onUpdated() { // get the update progress div var updateProgressDiv = $get('updateProgressDiv'); // make it invisible updateProgressDiv.style.display = 'none'; }
Here is the complete markup for the page ...
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head id="Head1" runat="server"> <title>Untitled Page</title> <script type="text/javascript" language="javascript"> function onUpdating(){ // get the update progress div var updateProgressDiv = $get('updateProgressDiv'); // make it visible updateProgressDiv.style.display = ''; // get the gridview element var gridView = $get('<%= this.gvCustomers.ClientID %>'); // get the bounds of both the gridview and the progress div var gridViewBounds = Sys.UI.DomElement.getBounds(gridView); var updateProgressDivBounds = Sys.UI.DomElement.getBounds(updateProgressDiv); // do the math to figure out where to position the element (the center of the gridview) var x = gridViewBounds.x + Math.round(gridViewBounds.width / 2) - Math.round(updateProgressDivBounds.width / 2); var y = gridViewBounds.y + Math.round(gridViewBounds.height / 2) - Math.round(updateProgressDivBounds.height / 2); // set the progress element to this position Sys.UI.DomElement.setLocation (updateProgressDiv, x, y); } function onUpdated() { // get the update progress div var updateProgressDiv = $get('updateProgressDiv'); // make it invisible updateProgressDiv.style.display = 'none'; } </script> </head> <body> <form id="form" runat="server"> <asp:ScriptManager ID="scriptManager" runat="server" /> <div> <asp:SqlDataSource ID="sqldsCustomers" runat="server" SelectCommand="select customerid, companyname, contactname, contacttitle from dbo.customers" SelectCommandType="Text" ConnectionString="server=mberseth;database=northwind;Trusted_Connection=yes;" /> <p> Example of using an UpdatePanelAnimationExtender to place an animated gif over a GridView while the GridView is being refreshed. </p> <br /> <table border="0" width="95%"> <tr> <td align="center">Customer ID</td> <td align="right"><asp:TextBox ID="txtCustomerID" runat="server" /></td> <td align="center">Company Name</td> <td align="right"><asp:TextBox ID="txtCompanyName" runat="server" /></td> <td align="center">Contact Name</td> <td align="right"><asp:TextBox ID="txtContactName" runat="server" /></td> </tr> <tr> <td colspan="6" align="right"><asp:Button ID="btnSearch" runat="server" Width="75" Text="Search" OnClick="BtnSearch_Click" /></td> </tr> </table> <br /> <asp:Label ID="lblTitle" runat="server" Text="Customers" BackColor="lightblue" Width="95%" /> <asp:UpdatePanel ID="updatePanel" runat="server"> <Triggers> <asp:AsyncPostBackTrigger ControlID="btnSearch" EventName="Click" /> </Triggers> <ContentTemplate> <asp:GridView ID="gvCustomers" runat="server" AllowPaging="true" AllowSorting="true" PageSize="20" DataSourceID="sqldsCustomers" Width="95%"> <AlternatingRowStyle BackColor="aliceBlue" /> <HeaderStyle HorizontalAlign="Left" /> </asp:GridView> </ContentTemplate> </asp:UpdatePanel> <ajaxToolkit:UpdatePanelAnimationExtender ID="upae" BehaviorID="animation" runat="server" TargetControlID="updatePanel"> <Animations> <OnUpdating> <Parallel duration="0"> <%-- place the update progress div over the gridview control --%> <ScriptAction Script="onUpdating();" /> <%-- disable the search button --%> <EnableAction AnimationTarget="btnSearch" Enabled="false" /> <%-- fade-out the GridView --%> <FadeOut minimumOpacity=".5" /> </Parallel> </OnUpdating> <OnUpdated> <Parallel duration="0"> <%-- fade back in the GridView --%> <FadeIn minimumOpacity=".5" /> <%-- re-enable the search button --%> <EnableAction AnimationTarget="btnSearch" Enabled="true" /> <%--find the update progress div and place it over the gridview control--%> <ScriptAction Script="onUpdated();" /> </Parallel> </OnUpdated> </Animations> </ajaxToolkit:UpdatePanelAnimationExtender> <div id="updateProgressDiv" style="display: none; height: 40px; width: 40px"> <img src="Img/dot-net-green.gif" /> </div> </div> </form> </body> </html>
Comments
very useful article..thankss..
Matt,
Very interesting demos that you have on your site. Thanks for taking the time to put them up.
I have taken your code and applied it to an page of mine, but I am having some issues with Mozilla. It works fine in IE and your Grid Example works fine in both.
For some reason with mine, it fades properly in Mozilla, but when the panel is updated it does not fade back in, it actually fades out even lighter and stays that way. When it updates again, it fades darker and then when done fades back to the almost transparent state.
Differences from your example:
Using this with MasterPages,
Using Virtual Earth on the page, but not in the update panel.
I was wondering if you have run into this issue at all in your development. Thank you for your time.
Christian
Very cool! Very useful! Great work!
Thank you! I owe you a beer/drink/pat on the shoulder.
Bye
Alexander
thank you
Hi matt,
Your demo is very usefull.
I have a problem with my program. i have to updatePanel and two UpdatePanelAnimationExtender in the same page. but both of them executed when one of the update pannels is callbacked.
may you help me. thanks
Hi, nice demo, except Im having some problems with IE7, as well as the javascript code.
In IE7, after the UpdatePanel is refreshed, sometimes the gridview ends up being cut off, as if it cannot wrap some of the text, or dynamically resize itself. This only happens when I use the animation extender.
Another problem is that the javascript code to place the gif over the gridview doesnt seem to find the gridview properly (its always null) and therefore the gif is always at the bottom.
Any help would be appreciated.
Thanks
Hi Matt,
Great article! My grid is fading properly, the button is disabled properly...however my image is always at the bottom of the page. Is there a way I can just have it at the top left of the update panel?
Thanks!
Hi Matt,
works great, but for some reason, I cant see my image. Im wondering about the line:
Ive added an alert to the onUpdating function and this doesnt appear. Ive got AjaxControlToolkit v1.0.10123.0...
Thanks
Toast
Matt,
Cool demo. Im having problems with the animation extender in ie7. While fading the grid nack in, the contents of the grid are cut off.
Any help would be greatly appreciated.
TIA,
Chris
@Chris
Thanks for the feedback Chris. Would you mind posting the code in a comment or sending it to me at matt@mattberseth.com?
Thanks,
Matt
Hi Matt -
I have the same problem with the content in the gridview being cutoff, if the updatepanel RenderMode is set to inline. If the RenderMode is set to block, then the columns are squished together. This only happens when there is a UpdatePanelAnimationExtender on the page as well.
If you found the solution to chriss problem, could you please post back here?
Thanks!
thank you thank you thank you
Nice example.. but I have question about the styles on the page...
Using IE7 the style of the text on page 1 is different to all subsequent pages.. it seems that the page LOOSES the style as set once the updatepanel comes into play and reverts to the browser default (at least with IE7) ... am I mad? Any comments/workarounds?
Matt,
Great article! Thanks for sharing... exactly what I was looking for today!
Hi Matt,
Its really a great article and it helps me in acheving my goals.
Thanks once again.
I m using a Master Page and in the Content PAge there is a grid view.
while using var gridView = $get();
I m not getting the grid view element.
Pls help.
Hi!
Great post!
If you dont want to show the gif if the grid is empty (no rows) you can modify the javascript function onUpdating() to show the div only if the grid is visible, just like this:
function onUpdating(){
// get the update progress div
var updateProgressDiv = $get(updateProgressDiv);
// get the gridview element
var gridView = $get();
var v = Sys.UI.DomElement.getVisibilityMode(gridView);
if (v)
{
// make it visible
updateProgressDiv.style.display = ;
// get the bounds of both the gridview and the progress div
var gridViewBounds = Sys.UI.DomElement.getBounds(gridView);
var updateProgressDivBounds = Sys.UI.DomElement.getBounds(updateProgressDiv);
// do the math to figure out where to position the element (the center of the gridview)
var x = gridViewBounds.x + Math.round(gridViewBounds.width / 2) - Math.round(updateProgressDivBounds.width / 2);
var y = gridViewBounds.y + Math.round(gridViewBounds.height / 2) - Math.round(updateProgressDivBounds.height / 2);
// set the progress element to this position
Sys.UI.DomElement.setLocation (updateProgressDiv, x, y);
}
}
Animation and loading data in example at all are not bound between itself, try more data and see.
Unholy english? May be.
I m using a Master Page and the Content Page had a grid view.
var gridView = $get(); is returning me NULL
Pls help.
I found a bug with the UpdatePanelAnimationExtender and I was curious if anyone else has seen this issue.
I am setting the focus of a textbox when the page loads. Everything worked fine until I added the UpdatePanelAnimationExtender to the page. I implemented it the same way as this awesome example and the functionality of the animation works great it just seems to lose focus of the textbox.
Any ideas as to why this is happening?
P.S. Matt, your blog rules. Every .net blog should be in your format(post, live demo)! You da mon!
i have an compilation error:
Could not load file or assembly 'System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.
may anyone help me?
I really like the demo.
Is there a resolution for Chris' gridview clipping issue?
Wonder if this is a bug in the Update Panel Animation Extender as my right-most columns disappear during the fade out.
Very good article.
Still need a little after the fadeIn, the font distorted.
Any ideas how to fix it?
Hi!, I have the same problem tahn Ed, any solution with the UpdatePanelAnimationExtender??.
Thanks!