Better Algorithm for Finding UpdatePanel that will be Updated During Page Request





4.00/5 (1 vote)
A better algorithm for finding UpdatePanel that will be updated during page request
Introduction
The other day, I was experimenting with finding which UpdatePanel will be updated during page postback.
I found out that my solution was not working correctly for complex triggers, like user controls with custom events, which will trigger async postbacks and update of panel.
Or for grids with buttons. It was a big issue. Also it was not pointing to the correct UpdatePanel
if name of the control was not entirely unique (for example, when you have multiple same custom controls on page). It would return the first panel, even if it wasn't updating.
So here is the updated code:
public static UpdatePanel FindAsyncPostBackUpdatePanel(this Page page)
{
var scriptManager = ScriptManager.GetCurrent(page);
var pageRequestMngr = scriptManager.GetNonPublicProperty
<object>("PageRequestManager");
var updatePanels = pageRequestMngr.GetNonPublicField
<List<UpdatePanel>>("_allUpdatePanels");
var source = page.FindControl(scriptManager.AsyncPostBackSourceElementID);
UpdatePanel parentUp = null;
//check if is child of update parent with children as triggers
Control parent = source.Parent;
while (parent != null && parentUp == null)
{
parent = parent.Parent;
parentUp = parent as UpdatePanel;
if (parentUp != null && (CheckIfPostbackSourceInTriggers
(source, parentUp) || parentUp.ChildrenAsTriggers
|| (parentUp.IsInPartialRendering ||
parentUp.GetNonPublicProperty<bool>("RequiresUpdate"))))
{
break;
}
parentUp = null;
}
if (parentUp != null) return parentUp;
foreach (var up in updatePanels)
{
if (CheckIfPostbackSourceInTriggers(source, up))
return up;
}
return null;
}
private static bool CheckIfPostbackSourceInTriggers(Control source, UpdatePanel up)
{
foreach (var trigger in up.Triggers)
{
var t = trigger as AsyncPostBackTrigger;
if (t == null)
{
continue;
}
if (t.GetNonPublicField<Control>
("_associatedControl").UniqueID == source.UniqueID)
{
return true;
}
}
return false;
}
What has Changed?
- I added code for traversing parent controls of our source control. Most of the time control that is causing post back is children of
UpdatePanel
. Such a loop is much quicker than finding out all ofUpdatePanel
s, and checking its triggers.Also if grid with some grid-specific event caused
UpdatePanel
to update, this grid probably will be child ofUpdatePanel
and so will be button from that grid. Still it's not ideal. If you have grid with some entities (customers
for example), and you want to click at somecustomer
will open its edit view inUpdatePanel
in some other part of page.Source
andUpdatePanel
are not in child-parent relation.If source is child of
UpdatePanel
method will check ifChildrenAsTriggers
istrue
- panel will be updated because it's triggered by child.If
IsInPartialRendering
flag andRequiresUpdate
, after some test I can say that that this flag indicates ifUpdatePanel
will be updated. The interesting thing is that the first flag was nottrue
even if givenUpdatePanel
was indeed updating. I don't know why. But the second flag non-public property wastrue
in those situations. - Checking only for control Id was not reliable since it doesn't have to be unique for page. That's why I am checking for unique id, of non-public field with trigger control instance and source unique id. That has to give the correct answer only for one control, but is much slower since it is using reflection.
That's it for now, but I feel that I will have to revise that code once again soon.