none
Ajax ModalPopupExtender fails to get Z-order right when nesting calls RRS feed

  • Question

  • The scenario I am trying to support is that of a base web form which displays data.  However, that form has the ability to support minor edits.  In this case we are using a basic button to invoke a modal dialogue (Ajax ModalDialogExtender) with the user, in which those edits will be performed.  To support this various validations are required.  The way I support the display of validation messages is the Ajax ModalDialogExtender.  Therefore the result of this is the need to nest calls to this feature. This seems to work fine when calls to ModalDialogExtender are client side invoked, but the problems start when you need server side support to assist with the validations.

    This question includes a full VS 2017 project.  It is very minimal and attempts to demonstrate the issue rather than be to pretty! The project references AjaxControlToolkit.15.1.4.0.

    The project is mainly HTML with embedded JS and CSS Style.  There is a very small amount of code behind in VB.

    <%@ Page Language="vb" AutoEventWireup="false" CodeBehind="ModalFromModal.aspx.vb" Inherits="ModalFromModal.frmMain" %>
    <%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>Modal from modal</title>
        <script type="text/javascript">
            function ShowDialog() {
                $find("frmDialog").show();
                var hfld = document.getElementById("bHfdDialogActive");
                hfld.value = 1;
                return false;
            }
            function HideDialog() {
                $find("frmDialog").hide();
                var hfld = document.getElementById("bHfdDialogActive");
                hfld.value = 0;
                return false;
            }
            function ShowMsg() {
                $find("frmMsg").show();
                return false;
            }
            function CheckMyData() {
                var htxtMyWord = document.getElementById("txtMyWord");
                var pos = htxtMyWord.value.search(" ");
                if (pos != -1) {
                    var hWarning = document.getElementById("lblWarning");
                    hWarning.innerText = "Spaces are not allowed";
                    $find("frmMsg").show();
                    return false;
                }
                return true;
            }
        </script>
        <style>
            .mpxMsg {
                z-index:1001;
            }
            .mpxDialog {
                z-index:1000;
            }
            .errmsg {
                text-align: center;
            }
            .errpnl {
                width: 400px;
            }
            .pnlDialog {
                width: 600px;
                height:200px;
            }
        </style>
    </head>
    <body>
        <form id="frmMain" runat="server">
            <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
            <div>
                <h1>Modal from modal - Base form</h1>
                <asp:Button ID="Button1" runat="server" Text="Edit data"  OnClientClick="return ShowDialog();" />
            </div>
            <asp:HiddenField ID="hfdForModel" runat="server" />
            <asp:ModalPopupExtender
                ID="frmMsg"
                TargetControlID="hfdForModel"
                runat="server"
                BackgroundCssClass="mpxMsg"
                DropShadow="true"
                PopupControlID="pnlIssues"  >
            </asp:ModalPopupExtender>          
            <asp:Panel ID="pnlIssues" runat="server" BorderColor="Black" BorderStyle="Outset"  BorderWidth="2" BackColor="White" style="display:none" CssClass="errpnl" >
                <div class="errmsg">
                    <asp:Label ID="lblHdr" runat="server" text="Information" style="font-weight: bold;"/>
                    <br /><br />
                    <asp:Label ID="lblWarning" runat="server" > </asp:Label>
                    <br />
                    <button type="button" onclick="$find('frmMsg').hide();" class="msgbutton">OK</button>
                </div>
            </asp:Panel>
    
            <asp:HiddenField ID="bHfdDialogActive" runat="server" />
            <asp:HiddenField ID="hfDialogTarg" runat="server" />
            <asp:ModalPopupExtender
                ID="frmDialog"
                TargetControlID="hfDialogTarg"
                runat="server"
                BackgroundCssClass="mpxDialog"
                DropShadow="true"
                PopupControlID="pnlDialog"  >
            </asp:ModalPopupExtender>
            <asp:Panel ID="pnlDialog" runat="server" BorderColor="Black" BorderStyle="Outset"  BorderWidth="2" BackColor="White" style="display:none" CssClass="pnlDialog" >
                <h2>Dialogue - edit</h2>
                <asp:Label ID="lblMyWord" runat="server" Text="My word"></asp:Label>
                <asp:TextBox ID="txtMyWord" runat="server"></asp:TextBox>
                <asp:Button ID="cmdCheck" runat="server" Text="Check" OnClientClick="return CheckMyData();" />
                <br /><br />
                <asp:Button ID="cmdClose" runat="server" Text="Close" OnClientClick="HideDialog();" />
            </asp:Panel>
        </form>
    </body>
    </html>

    Public Class frmMain
        Inherits System.Web.UI.Page
        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            If IsPostBack Then
                If bHfdDialogActive.Value = "1" Then frmDialog.Show()
                If Not WordInDatabase() Then
                    lblWarning.Text = "Your word is not on file"
                    frmMsg.Show()
                End If
            End If
        End Sub
        Function WordInDatabase() As Boolean
            Return False
        End Function
    End Class

    The HTML covers the base form, a declaration of a frmDialog which is launched from the base form button (edit).  There is also a declaration of frmMsg, used to report a validation error to the user.

    The edit form has a textbox a check button and a close button.  The idea is that when the check button is pressed, validation is in two stages: 

    First, client side, there is a check to make sure only a single word is entered.  The purpose of this is to illustrate how I want it to work.  i.e. That the base form is in background, the edit form overlays that and finally the validation message overlays that. 

    Second stage of validation is the perform a lookup on a database to see if that word exists.  I have not bothered to include the code behind for that, other than a shell function which always returns a false to invoke the same frmMsg from server side. 

    The problem: Unfortunately, the result of this is that whilst both the frmDialog and frmMsg are issued, the frmDialog overlays the frmMsg.  If you use the frmDialog close button, you can see the frmMsg.

    I have seen other articles where the use of a styled z-order which seems to be relevant.  You will see I have implemented this, but it seems to have no benefit.  Other articles also refer to JS based ToTop feature, but I could never find enough details to understand how to try this out.

    You will see that I force the re-display of the frmDialog for each postback, based on a hidden field.  There might be a more elegant way of doing this?  I did experiment with calling that from LoadComplete but that made no difference.


    Wednesday, August 21, 2019 7:40 AM

Answers

  • I over simplified the code behind for a fully working solution.  Here is an updated version of the full project.

    Public Class frmMain
        Inherits System.Web.UI.Page
        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            If IsPostBack Then
                If bHfdDialogActive.Value = "1" Then frmDialog.Show()
    
            End If
        End Sub
        Protected Sub cmdCheck_Click(sender As Object, e As EventArgs) Handles cmdCheck.Click
            If Not WordInDatabase() Then
                lblWarning.Text = "Your word is not on file"
                frmMsg.Show()
            End If
        End Sub
        Function WordInDatabase() As Boolean
            ' Place code here to interact with database and return true or false as appropriate
            Return False
        End Function
    End Class

    In c#...

    using System;
    
    public class frmMain : System.Web.UI.Page
    {
        protected void Page_Load(object sender, System.EventArgs e)
        {
            if (System.Web.UI.Page.IsPostBack)
            {
                if (bHfdDialogActive.Value == "1")
                    frmDialog.Show();
            }
        }
        protected void cmdCheck_Click(object sender, EventArgs e)
        {
            if (!WordInDatabase())
            {
                lblWarning.Text = "Your word is not on file";
                frmMsg.Show();
            }
        }
        public bool WordInDatabase()
        {
            // Place code here to interact with database and return true or false as appropriate
            return false;
        }
    }
    

    And the re-ordered HTML...

    <%@ Page Language="vb" AutoEventWireup="false" CodeBehind="ModalFromModal.aspx.vb" Inherits="ModalFromModal.frmMain" %>
    <%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>Modal from modal</title>
        <script type="text/javascript">
            function ShowDialog() {
                $find("frmDialog").show();
                var hfld = document.getElementById("bHfdDialogActive");
                hfld.value = 1;
                return false;
            }
            function HideDialog() {
                $find("frmDialog").hide();
                var hfld = document.getElementById("bHfdDialogActive");
                hfld.value = 0;
                return false;
            }
            function ShowMsg() {
                $find("frmMsg").show();
                //$find("frmMsg").focus();
                return false;
            }
            function HideMsg() {
                $find("frmMsg").hide();
                return false;
            }
            function CheckMyData() {
                var htxtMyWord = document.getElementById("txtMyWord");
                var pos = htxtMyWord.value.search(" ");
                if (pos != -1) {
                    var hWarning = document.getElementById("lblWarning");
                    hWarning.innerText = "Spaces are not allowed";
                    $find("frmMsg").show();
                    return false;
                }
                return true;
            }
        </script>
        <style>
            .mpxMsg {
                z-index:1001;
            }
            .mpxDialog {
                z-index:1000;
            }
            .errmsg {
                text-align: center;
            }
            .errpnl {
                width: 400px;
            }
            .pnlDialog {
                width: 600px;
                height:200px;
            }
        </style>
    </head>
    <body>
        <form id="frmMain" runat="server">
            <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
            <div>
                <h1>Modal from modal - Base form</h1>
                <asp:Button ID="Button1" runat="server" Text="Edit data"  OnClientClick="return ShowDialog();" />
            </div>
    
            <asp:HiddenField ID="bHfdDialogActive" runat="server" />
            <asp:HiddenField ID="hfDialogTarg" runat="server" />
            <asp:ModalPopupExtender
                ID="frmDialog"
                TargetControlID="hfDialogTarg"
                runat="server"
                BackgroundCssClass="mpxDialog"
                DropShadow="true"
                PopupControlID="pnlDialog"  >
            </asp:ModalPopupExtender>
            <asp:Panel ID="pnlDialog" runat="server" BorderColor="Black" BorderStyle="Outset"  BorderWidth="2" BackColor="White" style="display:none" CssClass="pnlDialog" >
                <h2>Dialogue - edit</h2>
                <asp:Label ID="lblMyWord" runat="server" Text="My word"></asp:Label>
                <asp:TextBox ID="txtMyWord" runat="server"></asp:TextBox>
                <asp:Button ID="cmdCheck" runat="server" Text="Check" OnClientClick="return CheckMyData();" />
                <br /><br />
                <asp:Button ID="cmdClose" runat="server" Text="Close" OnClientClick="HideDialog();" />
            </asp:Panel>
    
            <asp:HiddenField ID="hfdForModel" runat="server" />
            <asp:ModalPopupExtender
                ID="frmMsg"
                TargetControlID="hfdForModel"
                runat="server"
                BackgroundCssClass="mpxMsg"
                DropShadow="true"
                PopupControlID="pnlIssues"  >
            </asp:ModalPopupExtender>          
            <asp:Panel ID="pnlIssues" runat="server" BorderColor="Black" BorderStyle="Outset"  BorderWidth="2" BackColor="White" style="display:none" CssClass="errpnl" >
                <div class="errmsg">
                    <asp:Label ID="lblHdr" runat="server" text="Information" style="font-weight: bold;"/>
                    <br /><br />
                    <asp:Label ID="lblWarning" runat="server" > </asp:Label>
                    <br />
                    <button type="button" onclick="$find('frmMsg').hide();" class="msgbutton">OK</button>
                </div>
            </asp:Panel>
        </form>
    </body>
    </html>

    • Marked as answer by Andrew2014 Saturday, August 24, 2019 9:53 AM
    Saturday, August 24, 2019 9:52 AM

All replies

  • Hi Andrew2014,

    Sorry for delay in reply.

    Based on your description, in JS, you could try to write "window.focus()" to top your form,

    in VB, you could use windows API function "SetWindowPos" to implement this feature.

    Private Declare Function SetWindowPos Lib "user32" _
       (ByVal hwnd As Long,
        ByVal hWndInsertAfter As Long,
        ByVal x As Long, ByVal y As Long,
        ByVal cx As Long, ByVal cy As Long,
        ByVal wFlags As Long) As Long
    
        Private Const HWND_TOPMOST = -1
        Private Const SWP_SHOWWINDOW = &H40
    
        Private Sub Form_load()
            Call SetWindowPos(Me.hwnd, Me.HWND_TOPMOST, 0, 0, 0, 0, Me.SWP_SHOWWINDOW)
        End Sub

    Please refer more here: SetWindowPos function and function sample

    Hope it could help you.

    Best Regards,

    Dylan

    Note: This response contains a reference to a third-party World Wide Web site. Microsoft is providing this information as a convenience to you. 

    Microsoft does not control these sites and has not tested any software or information found on these sites; Therefore, Microsoft cannot make any representations regarding the quality, safety, or suitability of any software or information found there.

    There are inherent dangers in the use of any software found on the Internet, and Microsoft cautions you to make sure that you completely understand the risk before retrieving any software from the Internet


    MSDN Community Support Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com



    Friday, August 23, 2019 7:35 AM
  • Thanks for your reply Dylan,

    I only just got a chance to review your suggestions.

    The first one is not really going to help, as there is no JS involved in the issue of the frmMsg.Show from the code behind.  Remember everything is fine if the invocation if frmMsg happens from the client side.  That's demonstrated by the initial validation for a single word.

    The second suggestion looks to be relevant to a desktop application to me?  Sure, its Windows that's controlling what's on top of what in the desktop world, but as you know this is about a web deployed application. 

    To me, this looks to be about the sequence of events.  Ajax JS is in control of what order modal forms are painted in.

    I just tried something and it looks like a sort of fix!

    The HTML is currently something like as follows (at a high level)...

    • Base form
    • Modal popup extender for frmMsg
    • Modal popup extender for frmDialog

    What if the order it repaints multiple modal forms is down to nothing more than the order of the code?

    • Base form
    • Modal popup extender for frmDialog
    • Modal popup extender for frmMsg

    Just ordering the declarations so that the frm you want on top is last seems to do the trick!  I will do some more testing and then mark this as a solution if there are no glitches.

    Thanks.

    Friday, August 23, 2019 3:50 PM
  • I over simplified the code behind for a fully working solution.  Here is an updated version of the full project.

    Public Class frmMain
        Inherits System.Web.UI.Page
        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            If IsPostBack Then
                If bHfdDialogActive.Value = "1" Then frmDialog.Show()
    
            End If
        End Sub
        Protected Sub cmdCheck_Click(sender As Object, e As EventArgs) Handles cmdCheck.Click
            If Not WordInDatabase() Then
                lblWarning.Text = "Your word is not on file"
                frmMsg.Show()
            End If
        End Sub
        Function WordInDatabase() As Boolean
            ' Place code here to interact with database and return true or false as appropriate
            Return False
        End Function
    End Class

    In c#...

    using System;
    
    public class frmMain : System.Web.UI.Page
    {
        protected void Page_Load(object sender, System.EventArgs e)
        {
            if (System.Web.UI.Page.IsPostBack)
            {
                if (bHfdDialogActive.Value == "1")
                    frmDialog.Show();
            }
        }
        protected void cmdCheck_Click(object sender, EventArgs e)
        {
            if (!WordInDatabase())
            {
                lblWarning.Text = "Your word is not on file";
                frmMsg.Show();
            }
        }
        public bool WordInDatabase()
        {
            // Place code here to interact with database and return true or false as appropriate
            return false;
        }
    }
    

    And the re-ordered HTML...

    <%@ Page Language="vb" AutoEventWireup="false" CodeBehind="ModalFromModal.aspx.vb" Inherits="ModalFromModal.frmMain" %>
    <%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>Modal from modal</title>
        <script type="text/javascript">
            function ShowDialog() {
                $find("frmDialog").show();
                var hfld = document.getElementById("bHfdDialogActive");
                hfld.value = 1;
                return false;
            }
            function HideDialog() {
                $find("frmDialog").hide();
                var hfld = document.getElementById("bHfdDialogActive");
                hfld.value = 0;
                return false;
            }
            function ShowMsg() {
                $find("frmMsg").show();
                //$find("frmMsg").focus();
                return false;
            }
            function HideMsg() {
                $find("frmMsg").hide();
                return false;
            }
            function CheckMyData() {
                var htxtMyWord = document.getElementById("txtMyWord");
                var pos = htxtMyWord.value.search(" ");
                if (pos != -1) {
                    var hWarning = document.getElementById("lblWarning");
                    hWarning.innerText = "Spaces are not allowed";
                    $find("frmMsg").show();
                    return false;
                }
                return true;
            }
        </script>
        <style>
            .mpxMsg {
                z-index:1001;
            }
            .mpxDialog {
                z-index:1000;
            }
            .errmsg {
                text-align: center;
            }
            .errpnl {
                width: 400px;
            }
            .pnlDialog {
                width: 600px;
                height:200px;
            }
        </style>
    </head>
    <body>
        <form id="frmMain" runat="server">
            <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
            <div>
                <h1>Modal from modal - Base form</h1>
                <asp:Button ID="Button1" runat="server" Text="Edit data"  OnClientClick="return ShowDialog();" />
            </div>
    
            <asp:HiddenField ID="bHfdDialogActive" runat="server" />
            <asp:HiddenField ID="hfDialogTarg" runat="server" />
            <asp:ModalPopupExtender
                ID="frmDialog"
                TargetControlID="hfDialogTarg"
                runat="server"
                BackgroundCssClass="mpxDialog"
                DropShadow="true"
                PopupControlID="pnlDialog"  >
            </asp:ModalPopupExtender>
            <asp:Panel ID="pnlDialog" runat="server" BorderColor="Black" BorderStyle="Outset"  BorderWidth="2" BackColor="White" style="display:none" CssClass="pnlDialog" >
                <h2>Dialogue - edit</h2>
                <asp:Label ID="lblMyWord" runat="server" Text="My word"></asp:Label>
                <asp:TextBox ID="txtMyWord" runat="server"></asp:TextBox>
                <asp:Button ID="cmdCheck" runat="server" Text="Check" OnClientClick="return CheckMyData();" />
                <br /><br />
                <asp:Button ID="cmdClose" runat="server" Text="Close" OnClientClick="HideDialog();" />
            </asp:Panel>
    
            <asp:HiddenField ID="hfdForModel" runat="server" />
            <asp:ModalPopupExtender
                ID="frmMsg"
                TargetControlID="hfdForModel"
                runat="server"
                BackgroundCssClass="mpxMsg"
                DropShadow="true"
                PopupControlID="pnlIssues"  >
            </asp:ModalPopupExtender>          
            <asp:Panel ID="pnlIssues" runat="server" BorderColor="Black" BorderStyle="Outset"  BorderWidth="2" BackColor="White" style="display:none" CssClass="errpnl" >
                <div class="errmsg">
                    <asp:Label ID="lblHdr" runat="server" text="Information" style="font-weight: bold;"/>
                    <br /><br />
                    <asp:Label ID="lblWarning" runat="server" > </asp:Label>
                    <br />
                    <button type="button" onclick="$find('frmMsg').hide();" class="msgbutton">OK</button>
                </div>
            </asp:Panel>
        </form>
    </body>
    </html>

    • Marked as answer by Andrew2014 Saturday, August 24, 2019 9:53 AM
    Saturday, August 24, 2019 9:52 AM