In the last couple of weeks I have been learning the ASP.Net Ajax extensions and Ajax Control Toolkit. It really is an amazing framework for simple and complex web applications.
While I was practicing the technology, I notice that there was something missing. I couldn't update an UpdatePanel
from a JavaScript in the client side.
Why this is useful? Well, I'll give you an example:
Suppose we have a web site which has multiple update panel which are needed to be updated every 5 seconds (If an update has occurred in the data they display). The simple way to do this is to add a timer control from the extensions, and add a tick event every 5 seconds.
What's the problem with that? My team leader, Doron, found this article in msdn:
http://msdn.microsoft.com/msdnmag/issues/07/06/WickedCode/Default.aspx?loc=en
The article mainly deals with performance issues in the ASP.Net Ajax extensions. One of them refers to performance of the UpdatePanel
. When you are using an update panel in a web page, the whole request is posted back to the server when you want to update an update panel. That means that for each tick of the timer a regular request will be posted back to the server (I remind you, every 5 seconds). Now If you have even two or three GridView control, that could be very inefficient. So the solution is to create a javascript timer which every 5 seconds calls a WebMethod
from a web service, which checks if the data has been updated, and then the client needs to trigger a post back of the particular update panel, which contains that data.
How to I trigger an update in an UpdatePanel
in the client side?
At first I thought to create my own UpdatePanel
which inherits from the original. But that could be problematic, especially with existing web forms.
I would need to replace all the panel with my own, not to mention problems with embedded resource in the original assembly that contains the UpdatePanel
control.
I decided to create an extender for the update panel which adds an update()
method to it's panel. Here's an example of how it should be used:
<script language=”javascript” type=”text/javascript”>
function Button1_onclick() {
var u = $get('<%= UpdatePanel1.ClientID %>');
u.update();
}
</script>
<asp:UpdatePanel ID=”UpdatePanel1″ runat=”server”>
<ContentTemplate>
<asp:TextBox ID=”TextBox1″ runat=”server”></asp:TextBox>
</ContentTemplate>
</asp:UpdatePanel>
<ysa:UpdatePanelExtender ID=”UpdatePanelExtender1″ runat=”server”
OnUpdated=”UpdatePanelExtender1_Updated” TargetControlID=”UpdatePanel1″>
</ysa:UpdatePanelExtender>
<input id=”Button1″ type=”button” value=”Client Button” onclick=”return Button1_onclick()” />
I created the extender using the extensibility infrastructure of the Ajax Control Toolkit. An extender contains three parts:
- Class which inherits from
ExtenderControlBase
, which contains the server side code. - Behavior: a JavaScript object which contains the client side code.
- Designer: optional. contains a definition of a designer for the extender.
To learn how to create an extender click here
In the UpdatePanelExtender
(catchy name), I simply added a hidden button to the update panel:
protected override void CreateChildControls()
{
// Adding the button that will be used to trigger the update :
Button updateButton = CreateUpdateButton();
TargetUpdatePanel.ContentTemplateContainer.Controls.Add(updateButton);
// In case the target panel defines that the child controls can not trigger a postback, add the update button click event
// to the triggers collection :
if (!TargetUpdatePanel.ChildrenAsTriggers)
{
AddUpdateButtonAsTrigger(updateButton);
}
UpdateButton = updateButton;
base.CreateChildControls();
}
private Button CreateUpdateButton()
{
Button updateButton = new Button();
updateButton.Style["display"] = “none“;
updateButton.Text = ClientID + “_UpdateButton“;
updateButton.Click += new EventHandler(UpdateButton_Click);
updateButton.ID = ClientID + “_UpdateButton“;
return updateButton;
}
private void AddUpdateButtonAsTrigger(Button updateButton)
{
AsyncPostBackTrigger t = new AsyncPostBackTrigger();
t.ControlID = updateButton.ClientID;
t.EventName = “Click“;
TargetUpdatePanel.Triggers.Add(t);
}
The update method simply calls the click()
method in the button control:
initialize : function() {
YsA.Web.UI.WebControls.UpdatePanelBehavior.callBaseMethod(this, ‘initialize‘);
// Adding the update method to the update panel :
var e = this.get_element();
e.update = Function.createDelegate(this,this.update);
}
The update method simply calls the “click” method in the button control:
update : function() {
var updateButton = $get(this._updateButtonClientID);
updateButton.click();
}
_updateButtonClientID
is a property that is initialized by the extender which contains the ID of the update button.
That's about it.
A solution which contains the source code and an example web form is attached to this post.
Known issues
I tried to create an event in the extender which will be triggered after the panel updates. I couldn't make it work. The final revision is in the source code, check it out. Maybe you could tell me what I did wrong.
I will be glad to read your comments, bugs you found, and improvement suggestions.
Have a great week.
Update
I've updated the extender. The updated version is in the UpdatePanelExtender Upgrade post. I've also removed the old version from this post.