Getting the UpdatePanel "responsible" for the postback

Sometimes, you might need to get a reference to the UpdatePanel which was "responsible" for the partial postback. It's important to understant that a postback will always be started by an existing HTML control and that the panel will only be used for delimiting the places where a partial postback might start. It's also important to understand that you can have a postback without associating an HTML control with an UpdatePanel (ie, you can start a partial postback by registering a control with the AsyncPostBackControl method; when you do this, you'll have a partial postback when a user clicks that button, even though the button is not inside the UpdatePanel nor is it set up as a trigger). ok, having said this, lets suppose you want to get a reference to the UpdatePanel that "was responsible for the postback" (ie, you want to get the UpdatePanel that contained the control that started the partial postback or that is associated with the control through an AsyncPostBackTrigger). The following code uses method extensions to add a method that will let you get a reference to that panel (in the cases where that is possible):

[Disclaimer: this code was written without testing so it might not work in complex scenarios.I might come back to it in the future, but for now I really don't have the time to test it in all the available scenarios]

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Web.UI;

namespace LA.Extensions
{
    public static class ScriptManagerExtension
    {
        public static UpdatePanel GetUpdatePanelAssociatedWithRefresh(this ScriptManager manager )
        {
            if( !manager.IsInAsyncPostBack)
            {
                return null;
            }
            UpdatePanel panel = null;
            Control ctlId = manager.Page.FindControl(manager.AsyncPostBackSourceElementID);
            if( ctlId == null )
            {
                return null;
            }

            panel = TryInUpdatePanels(ctlId);
            if( panel == null)
            {
                panel = SearchForTrigger(ctlId, manager);
            }

            return panel;
        }

        private static UpdatePanel SearchForTrigger(Control ctlId, ScriptManager manager)
        {
            Type pageRequestManagerType = Type.GetType("System.Web.UI.PageRequestManager,System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
            Type scriptManagerType = typeof (ScriptManager);

            Object pageRequestManager =
                scriptManagerType.InvokeMember("PageRequestManager",
                                                BindingFlags.NonPublic | BindingFlags.Instance |BindingFlags.GetProperty,
                                                null,
                                               manager, null, null);
            List<UpdatePanel> updatePanels =
                (List<UpdatePanel>)pageRequestManagerType.InvokeMember(
                                        "_allUpdatePanels",
                                        BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField,
                                        null, pageRequestManager, null, null );

            foreach(UpdatePanel panel in updatePanels)
            {
                foreach(UpdatePanelTrigger trigger in panel.Triggers)
                {
                    AsyncPostBackTrigger t = trigger as AsyncPostBackTrigger;
                    if (t == null)
                    {
                        continue;
                    }
                    if(String.Compare(t.ControlID, ctlId.UniqueID) == 0 )
                    {
                        return panel;
                    }
                }
            }

            return null;
        }

        private static UpdatePanel TryInUpdatePanels(Control ctlId)
        {
            if(ctlId is UpdatePanel)
            {
                return (UpdatePanel) ctlId;
            }

            Control parent = ctlId.Parent;
            while(parent != null )
            {
                if( parent is UpdatePanel && ((UpdatePanel)parent).ChildrenAsTriggers )
                {
                    return (UpdatePanel)parent;
                }
                parent = parent.Parent;
            }
            return null;
        }
    }
}

 

The following page shows how the previous extension can be used:

<%@ Page Language="C#" %>
<%@ Import Namespace="LA.Extensions" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        UpdatePanel panel = manager.GetUpdatePanelAssociatedWithRefresh();
        if (panel != null)
        {
            lbl.Text = panel.UniqueID;
        }
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager runat="server" id="manager" />
        <asp:updatepanel runat="server" id="panel" UpdateMode="Conditional">
            <ContentTemplate>
                <asp:Button runat="server" id="bt1" Text="inside panel" />
                <br />
                <%=DateTime.Now.ToString() %>
                <br />
                <asp:Label runat="server" ID="lbl" />
            </ContentTemplate>
            <Triggers>
                <asp:AsyncPostBackTrigger ControlID="bt2" EventName="Click" />
            </Triggers>
        </asp:updatepanel>
        <asp:Button runat="server" id="bt2" Text="outside panel" />
    </form>
</body>
</html>

The important thing to notice here is the use of the Import directive so that the method extension is introduced on the current namespace. As I've said before, the objective of the code is to show what you might have to write to get the primary panel associated with the partial postback...

Leave a Comment

(required) 
(required) 
(optional)
(required)