AjaxControlToolkit and Master Pages and ResolveControlID

I’ve been using the AjaxControlToolkit for a bit and I quite like it – there may be better Ajax frameworks out there, but this one is really well integrated into .NET, and that’s good for me.

Anyway, I had some bother with the ModalPopup when used inside a page which uses a Master page. I was putting the the CSS for my popup at the end of my <asp:Content /> but things like the initial positioning and the dragging were all messed up. I fixed that by

  1. Creating another <asp:ContentPlaceHolder /> on my master page which was outside of the <div /> tags with the CSS positioning, and
  2. Moving all the Ajax related code into this new placeholder.

So, the Master page looks like this:

<body>
    <form id="form2" runat="server">
        <ajaxToolkit:ToolkitScriptManager ID="MasterTookitScriptManager" runat="server" />
        <asp:ContentPlaceHolder ID="slotAjax" runat="server" />
        <div id="topcontainer">
            <div id="logostrip">
                <div id="logo">
                </div>
                <div id="dsTitle">
                    Document Scanning
                </div>
                <div id="formTitle" runat="server" class="formTitle">
                    Form Title
                </div>
                <div id="userInfo" runat="server" class="userInfo">
                </div>
            </div>
            <div id="content">
                <div id="innercontent">
                    <asp:ContentPlaceHolder ID="slotMain" runat="server" />
                </div>
            </div>
        </div>
    </form>
</body>

And the Ajax stuff on the page looks like this:

<asp:Content ID="fillAjax" runat="server" ContentPlaceHolderID="slotAjax">
    <ajaxToolkit:ModalPopupExtender runat="server"
        ID="programmaticModalPopup" BehaviorID="programmaticModalPopupBehavior"
        TargetControlID="cmdDefer" PopupControlID="pnlPopup"
        BackgroundCssClass="modalBackground"
        DropShadow="True" RepositionMode="RepositionOnWindowResize"
        CancelControlID="cmdPopupCancel" PopupDragHandleControlID="pnlPopupDragHandle" OnResolveControlID="programmaticModalPopup_ResolveControlID" />
    <hr />
    <asp:Panel ID="pnlPopup" runat="server" Style="display: none"
        CssClass="modalPopup" DefaultButton="cmdPopupOK">
        <asp:Panel ID="pnlPopupDragHandle" runat="server"
            Style="cursor: move; background-color: #DDDDDD;
            border: solid 1px Gray; color: Black;
            text-align: center;">
            <div>
                <p>
                    How long would like to defer this document
                    for?
                </p>
            </div>
        </asp:Panel>
        <div>
            <asp:RadioButtonList ID="radPeriod" runat="server" ...
            <p style="text-align: center;">
                <asp:Button ID="cmdPopupOK" runat="server"
                    Text="OK" OnClick="cmdPopupOK_Click"
                    ValidationGroup="Deferral" />
                <asp:Button ID="cmdPopupCancel" runat="server"
                    Text="Cancel" CausesValidation="false"
                    OnClick="cmdPopupCancel_Click" />
            </p>
        </div>
    </asp:Panel>
</asp:Content>

Now there’s one problem remaining: the TargetControlID="cmdDefer" attribute refers to a button in a different <asp:Content /> and the default control ID resolution implementation in ExtenderControlBase.cs doesn’t find my control. This shows up as an exception in the Page Render method:

Server Error in ‘/Uncoded’ Application.


The TargetControlID of ‘programmaticModalPopup’ is not valid. A control with ID ‘cmdDefer’ could not be found.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: The TargetControlID of ‘programmaticModalPopup’ is not valid. A control with ID ‘cmdDefer’ could not be found.

Source Error:

Line 364:        protected override void OnPreRender(EventArgs e)
Line 365:        {
Line 366:            base.OnPreRender(e);
Line 367:
Line 368:            if (Enabled && TargetControl.Visible)

Source File: C:\Dev\AjaxControlToolkit\AjaxControlToolkit\ExtenderBase\ExtenderControlBase.cs    Line: 366

The designers of the toolkit already thought of this though, and if they can’t resolve your ControlID, they’ll ask you to do it for them by raising the ResolveControlID event. So the final part of the puzzle is to catch the event and respond to it:

protected void programmaticModalPopup_ResolveControlID( object sender, AjaxControlToolkit.ResolveControlEventArgs e )

{

    // The Ajax stuff needs to be inside a different ContentPlaceHolder on the master page because otherwise the master page CSS breaks it.

    // The default Control Id resolution in ExtenderControlBase fails to find cmdDefer because it is contained inside a different ContentPlaceHolder

    // So they raise this event for me and I resolve it for them.

    switch( e.ControlID )

    {

        case "cmdDefer":

            e.Control = cmdDefer;

            break;

    }

}

Job done!

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

2 Responses to AjaxControlToolkit and Master Pages and ResolveControlID

  1. Unknown says:

    Brilliant!!!!!!!!!!!!!!!!!!!!!!! Why I haven\’t run into this before I have no idea, but brilliant. I am now updating all of my custom ajax controls. THANK YOU!

  2. Steve C says:

    So how exactly is the event raised? Where do we put in the name of the function so it knows to call it?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s