So I'm finally getting around to spending a little more time with ATLAS. Today I'm looking at UpdatePanels which in concept are pretty damn cool, because they can make really short work of updating content on a page even if the page was designed with no AJAX concepts in mind.
An ATLAS UpdatePanel works by wrapping a section of your page with an UpdatePanel object. The panel acts as a container and marker that ASP.NET uses to decide what needs to be updated on a Page level callback. To do this you:
- Create your form without any thought to AJAX <g>
- Add an UpdatePanel around the section you want updated
- Add an Event Trigger to the UpdatePanel to have a source action
- Add a ScriptManager object to the page and set EnablePartialUpdates=true
And realistically that's it for simple things.
My sample that I've been using for simple AJAX tests is a listbox of Northwind customers, which on selection updates a customer record displayed in Textboxes.
Add the script manager:
<atlas:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="true">
</atlas:ScriptManager>
Wrap the Customer display area into an UpdatePanel:
<td valign="top"
style="padding-left: 20px; padding-top: 10px; padding-right: 10px;height: 435px;">
<atlas:UpdatePanel ID="CustomerUpdatePanel" runat="server">
<Triggers>
<atlas:ControlValueTrigger ControlID="lstCustomers" PropertyName="selectedIndex" />
</Triggers>
<ContentTemplate>
<asp:Label ID="Label1" runat="server" Text="Name:"></asp:Label><br />
<asp:TextBox ID="txtContactName" runat="server" Width="350px" Text="<%# this.Customer.Entity.Contactname %>"></asp:TextBox><br />
…etc…
</ContentTemplate>
</atlas:UpdatePanel>
</td>
Notice the trigger which ties the update to the SelectedIndex property. Note this is the SERVER SIDE property, which means that you still need AutoPostBack to true on the list.
But that's pretty much it. First shot: It works really well. Literally the 4 steps above and I've made a standard POSTback form able to use AJAX callbacks to bring down the updated customer data. No flicker – life is good.
It's a pretty slick concept – ATLAS basically goes back to the server and runs the page as it normally would, but when it comes time to render it's going to render only the UpdatePanel content plus the page header, including the all important ViewState. It then ships all of that back to the client. Nice!
Until you take a look at what's going over the wire! Because the ListBox by default is living in ViewState it's going back on the Callback POST buffer. And it also comes back from there server after the callback.There's goes our 'small' server side callback request.
So, thought #2: Turn off viewstate on the list. I now have a smaller payload going to back to the server, but it also doesn't work. Right – I need to rebind the list on every hit. So I add my DataBind() in Page_Load() on the list every time instead of just if (!Page.IsPostBack). But it still doesn't work because now ASP.NET can't reassign the SelectedValue properly and so my selection gets lost and the Customer data also doesn't get updated. So I have to move the databinding code into OnInit() so the list is bound prior to the PostBack data being assigned to the list. OnInit() wouldn't be my choice for databinding, normally, but it works.
Not quite as simple as it looks but still pretty cool because I didn't have to change much on the server and there's no client code even if I did have to understand how to deal with the list issue which IS different than a Page PostBack.
So far so good.
Ok, the next step is to also be able to update the List when a value is changed. And here my luck runs out. So I add a second UpdatePanel and wrap the List into it. I add another trigger for a Refresh button:
<atlas:UpdatePanel ID="ListUpdatePanel" runat="server">
<Triggers>
<atlas:ControlEventTrigger ControlID="btnRefresh" EventName="Click" />
</Triggers>
<ContentTemplate>
<asp:ListBox ID="lstCustomers" runat="server" Height="442px" Width="300px"
OnSelectedIndexChanged="lstCustomers_SelectedIndexChanged"
AutoPostBack="True" EnableViewState="false" >
</asp:ListBox>
</ContentTemplate>
</atlas:UpdatePanel>
Now there are two update panels on the form. When I run the form it actually still works, but not quite right. The problem is that both UpdatePanels are refreshing unconditionally. They're not refreshing based on which panel fired the event.
There's gotta be a way to check which Panel is updating and maybe then you can selectively update data on the Page. There's an IsUpdating property on the UpdatePanel control. Unfortunately it always returns false. It also looks like the wrong event id is getting sent back to the server. When I click on the list to select a customer record here's what I get over the wire:
ScriptManager1=ListUpdatePanel&__EVENTTARGET=lstCustomers&__EVENTARGUMENT=&__LASTFOCUS=&__VIEWSTATE=%2FwEPDwUKMTc4OTI4MjczNGRkCqAyB8haLbw3AeneYTyE7Hgahxc%3D&lstCustomers=CENTC&txtPK=&txtContactName=&txtCompany=&txtAddress=&txtCity=&txtRegion=&txtPostalCode=&txtCountry=&
ScriptManager1 is set to ListUpdatePanel – which is not the right panel that initiated the callback. The CustomerUpdatePanel was the one that fired the event.
So unless I'm missing something obvious (which is easy to do without any documentation) it looks like currently multiple UpdatePanels are just not supported. I hope this is something that will be addressed in future revs, because it seems that this mechanism would be great for enhancing existing applications without much code at all even if the code returned is bloated.
Other Posts you might also like