locked
Popup forms on Master Page RRS feed

  • Question

  • User1120190316 posted

    My web application has several popup forms used for data input.  These forms are invoked from a number of different pages, so I decided to move them onto the Master Page shared by these pages.  I have experimented moving one of the popup panels from aspx page to master page, along with the associated ModalPopupExtension tags and some javascript, and I get a compilation error with regard to btnPopTaskSave, the button on the popup that the user would click to save the data and close the form.  Here is the error:

    Compilation Error
    Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.

    Compiler Error Message: BC30506: Handles clause requires a WithEvents variable defined in the containing type or one of its base types.

    Source Error:
    Line 1072: End Function
    Line 1073:
    Line 1074: Protected Sub btnPopTaskSave_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnPopTaskSave.Click
    Line 1075:
    Line 1076: 'Get data from popup form pnlTask_Pop

    --------------------------

    What do I need to do to avoid this error?  

    If I may tack on a second question, how would I reference the ModalPopupExtender from server side vb code to close the popup?  I have been using the syntax, 
    "Dim strTaskName As String = CType(Master.FindControl("txtPopTaskName"), TextBox).Text" to reference other controls on the Master Page.  This works for textboxes, but the CType function will not accept ModalPopupExtender as an argument.

    Thank you for your help.

    Monday, April 27, 2020 6:00 AM

Answers

  • User1120190316 posted

    Success!

    Since last posting here, I have read a couple of articles that recommend creating an Event to run when the data is saved, i.e., after the stored procedure uspTaskPopup_Save has successfully run.   Then the panel on the content page can be updated by the event handler which would live on the content page.  Here is the relevant code:

    The following codebehind on the master page runs when the button on the popup form is clicked:

        Protected Sub btnPopTask_Save_Click(sender As Object, e As EventArgs) Handles btnPopTask_Save.Click
    
            'Get data from popup form pnlTask_Pop
            Dim strTaskID As String = CType(FindControl("hidPopTaskID"), HiddenField).Value.ToString
            If Not IsNumeric(strTaskID) Then strTaskID = "0"
            Dim strPostTaskID As String = CType(FindControl("hidPopPostTaskID"), HiddenField).Value.ToString
            If Not IsNumeric(strPostTaskID) Then strPostTaskID = "0"
    
    
            Dim strOwnerID As String = Session("OwnerID").ToString
            Dim strTaskName As String = CType(FindControl("txtPopTaskName"), TextBox).Text.Replace("'", "''")
            Dim strDisplayDate As String = CType(FindControl("txtPopTaskDisplayDate"), TextBox).Text
            Dim strListDate As String = CType(FindControl("hidPopTaskListDate"), HiddenField).Value.ToString
            Dim strDeadline As String = CType(FindControl("txtPopTaskDeadline"), TextBox).Text
            Dim bDone As Boolean = IsDate(CType(FindControl("txtPopTaskDateDone"), TextBox).Text)
            Dim strTaskNotes As String = CType(FindControl("txtPopTaskNotes"), TextBox).Text.Replace("'", "''")
            Dim strDateDone As String = CType(FindControl("txtPopTaskDateDone"), TextBox).Text
    
            Dim strGoalID As String = CType(FindControl("ddlPopTaskGoal"), DropDownList).SelectedValue.ToString
            Dim strGoalName As String = CType(FindControl("ddlPopTaskGoal"), DropDownList).SelectedItem.Text
            Dim intHighPriority As Integer = IIf(CType(FindControl("chkHighPriority"), CheckBox).Checked = True, 1, 0)
            Dim intIsGoal As Integer = IIf(CType(FindControl("chkIsGoal"), CheckBox).Checked = True, 1, 0)
            Dim intInactive As Integer = IIf(CType(FindControl("chkInactive"), CheckBox).Checked = True, 1, 0)
    
            'Update database
            Dim strSQL As String = "execute dbo.uspTaskPopup_Save " & _
                                    strTaskID & _
                                    ", " & strOwnerID & _
                                    ", '" & strTaskName & _
                                    "', '" & strDisplayDate & _
                                    "', '" & strDeadline & _
                                    "', " & strPostTaskID & _
                                    ", " & intHighPriority.ToString & _
                                    ", '" & strTaskNotes.Replace("<br />", vbCrLf) & _
                                    "', '" & strDateDone & _
                                    "', " & intIsGoal.ToString & _
                                    ", " & intInactive.ToString()
    
            'Stored procedure updates tblTask and returns TaskID of edited or added record
            Dim ReturnVal As Int32 = Convert.ToInt32(SqlHelper.ExecuteScalar(strSQL))
    
            'If ReturnVal indicates the sql succeeded, raise event that will update the content page
            If ReturnVal > 0 Then
    
                'Set error message to blank
                CType(FindControl("lblPopTaskError"), Label).Text = ""
    
                'Close form
                mpeTaskPop.Hide()
    
                'Let content page know about this
                RaiseEvent TaskSaved(Me, EventArgs.Empty)
    
            Else
                CType(FindControl("lblPopTaskError"), Label).Text = "An error occurred.  Unable to update task."
    
            End If
    
        End Sub
    

    As you can see, after it runs the stored procedure, it checks the value returned, and if the procedure ran successfully, it returns the ID number of the updated record.  If it was successful, the TaskSaved event is raised and the action switches to the event handler in the content file.

        Private Sub Master_TaskSaved(ByVal Sender As Object, ByVal e As EventArgs)
    
            GetSchedule(calFrom.SelectedDate, calTo.SelectedDate)
            tvDoList.ExpandAllNodes()
    
            'Update panel containing tvDoList
            updDoList.Update()
    
        End Sub

    GetSchedule() is a routine that revises the treeview tvDoList.

    I also added a line to the master page's code behind:

    Partial Class PPM
        Inherits System.Web.UI.MasterPage
    
        Public Event TaskSaved As EventHandler
    
        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            If Not IsPostBack Then
    
                With ScriptManager1
                    .RegisterAsyncPostBackControl(btnPopTask_Save)
                End With
    ...

    End Sub

    This creates the Event and then causes the btnPopTask_Save button to cause an asynch post-pack.

    Finally, I had to add a line of code to the content page's Sub Page_PreInit:

       Protected Sub Page_PreInit(sender As Object, e As EventArgs) Handles Me.PreInit
            AddHandler Master.TaskSaved, AddressOf Master_TaskSaved
    
        End Sub
    

    And now it runs.  Thank you for your help.  I hope the above is helpful to others.  I recommend the two articles that provided the information I needed.

    https://docs.microsoft.com/en-us/aspnet/web-forms/overview/older-versions-getting-started/master-pages/interacting-with-the-content-page-from-the-master-page-vb

    https://docs.microsoft.com/en-us/aspnet/web-forms/overview/older-versions-getting-started/master-pages/interacting-with-the-content-page-from-the-master-page-vb

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, April 29, 2020 3:12 PM

All replies

  • User1535942433 posted

    Hi Sheldon Penner,

    Compiler Error Message: BC30506: Handles clause requires a WithEvents variable defined in the containing type or one of its base types.

    Accroding to your description,you could try this way:

    Protected Sub btnPopTaskSave_Click(ByVal sender As Object, ByVal e As System.EventArgs) 
    
       
        End Sub 
    
    in aspx
    
    <asp:Button ID="btnPopTaskSave" runat="server" Text="manual login" OnClick ="btnPopTaskSave_Click"/>

    More details,you could refer to below article:

    https://forums.asp.net/t/1366892.aspx?error+Handles+clause+requires+a+WithEvents+variable+

    "Dim strTaskName As String = CType(Master.FindControl("txtPopTaskName"), TextBox).Text" to reference other controls on the Master Page.  This works for textboxes, but the CType function will not accept ModalPopupExtender as an argument.

    As far as I think,you could use the  DirectCast  function,

    Just like this:

    Dim mploginM As AjaxControlToolkit.ModalPopupExtender = DirectCast(Page.Master.FindControl("ModalPopupExtender1"), AjaxControlToolkit.ModalPopupExtender)

    Best regards,

    Yijing Sun

    Tuesday, April 28, 2020 6:10 AM
  • User1120190316 posted

    Thank you for your response, Yij Sun.  

    As you suggested, I removed the Handles clause from my Protected Sub btnPopTaskSave_Click and added the explicit OnClick to the button markup.  This time I got a different compilation error:  "BC30456: 'btnPopTaskSave_Click' is not a member of 'ASP.ppm_master'."  Apparently, the Master page cannot see controls and server code in its attached files.  (I may not have made it clear in my original post that the btnPopTaskSave_Click sub is not in the Master page's back end file but in the client page's.)  I will experiment with moving the vb code to the Master page's vb file  I anticipate a problem of updating controls on the main page, which will be different depending on which main page is attached to the Master page.  Is there a way for the Master page to get the name of its current client page and manipulate controls on that page?

    Since posting, I discovered a different solution to the second problem I described.  I appended "AjaxControlToolkit." to the front of the second argument of the CType function, and CType now knows what I'm talking about.  "CType(Master.FindControl("mpeTaskPop"), AjaxControlToolkit.ModalPopupExtender).Hide()"

    Tuesday, April 28, 2020 11:36 PM
  • User1120190316 posted

    Hello again, Yij Sun.

    I have moved btnPopTask_Save_Click from the content page's code behind to the master page's code behind.  This does seem to be the solution -- everything compiles normally and the popup even pops up!.  The problem now is to get the Master page to see the update panels on the Content pages so that, after entering or editing data on the popup form, the changes show up on the content page.  I have tried this:

    Dim upd = CType(cphMain.FindControl("updDoList"), UpdatePanel)
    upd.Update()

    The code above does not throw any errors, but it does not update the UpdatePanel.  (cphMain is the id of the ContentPlaceHolder on the master page that contains the update panel.)

    I need to also find a way for the Master page to determine which page is currently its Content page, since the panel to be updated has a different id in each case.  (I could, I suppose, give all these update panels the same name, but that strikes me as the kind of shortcut liable to bite me on the butt some time in the future.)  

    All these problems lead me to suspect that perhaps saving on the Master page is not the recommended solution for using the same popups on several content pages.  Previously, I had identical markup and code for each of these popup panels on each page, but I would hate to return to that.  Is there a better way to share popups among several pages?

    Here is the sub routine that now lives in the master page's code behind:

        Protected Sub btnPopTask_Save_Click(sender As Object, e As EventArgs) Handles btnPopTask_Save.Click
    
            'Get data from popup form pnlTask_Pop
            Dim strTaskID As String = CType(FindControl("hidPopTaskID"), HiddenField).Value.ToString
            If Not IsNumeric(strTaskID) Then strTaskID = "0"
            Dim strPostTaskID As String = CType(FindControl("hidPopPostTaskID"), HiddenField).Value.ToString
            If Not IsNumeric(strPostTaskID) Then strPostTaskID = "0"
    
    
            Dim strOwnerID As String = Session("OwnerID").ToString
            Dim strTaskName As String = CType(FindControl("txtPopTaskName"), TextBox).Text
            Dim strDisplayDate As String = CType(FindControl("txtPopTaskDisplayDate"), TextBox).Text
            Dim strListDate As String = CType(FindControl("hidPopTaskListDate"), HiddenField).Value.ToString
            Dim strDeadline As String = CType(FindControl("txtPopTaskDeadline"), TextBox).Text
            Dim bDone As Boolean = IsDate(CType(FindControl("txtPopTaskDateDone"), TextBox).Text)
            Dim strTaskNotes As String = CType(FindControl("txtPopTaskNotes"), TextBox).Text
            Dim strDateDone As String = CType(FindControl("txtPopTaskDateDone"), TextBox).Text
    
            Dim strGoalID As String = CType(FindControl("ddlPopTaskGoal"), DropDownList).SelectedValue.ToString
            Dim strGoalName As String = CType(FindControl("ddlPopTaskGoal"), DropDownList).SelectedItem.Text
    
            Dim intHighPriority As Integer = IIf(CType(FindControl("chkHighPriority"), CheckBox).Checked = True, 1, 0)
            Dim intIsGoal As Integer = IIf(CType(FindControl("chkIsGoal"), CheckBox).Checked = True, 1, 0)
            Dim intInactive As Integer = IIf(CType(FindControl("chkInactive"), CheckBox).Checked = True, 1, 0)
    
            'Update database
            Dim strSQL As String = "execute dbo.uspTaskPopup_Save " & _
                                    strTaskID & _
                                    ", " & strOwnerID & _
                                    ", '" & strTaskName & _
                                    "', '" & strDisplayDate & _
                                    "', '" & strDeadline & _
                                    "', " & strPostTaskID & _
                                    ", " & intHighPriority.ToString & _
                                    ", '" & strTaskNotes.Replace("<br />", vbCrLf) & _
                                    "', '" & strDateDone & _
                                    "', " & intIsGoal.ToString & _
                                    ", " & intInactive.ToString()
    
            'Stored procedure updates tblTask and returns TaskID of edited or added record
            Dim ReturnVal As Int32 = SqlHelper.ExecuteScalar(strSQL)
    
            Dim nodVal As String = "TaskID=" & strTaskID
            Dim nd As RadTreeNode = Nothing
    
            'If proc failed, ReturnVal = 0; otherwise, its the TaskID
            If ReturnVal > 0 Then
                'Hide popup form
                CType(FindControl("mpeTaskPop"), AjaxControlToolkit.ModalPopupExtender).Hide()
    
                DoListOutline.GetSchedule(DoListOutline.calFrom.SelectedDate, DoListOutline.calTo.SelectedDate)
                DoListOutline.tvDoList.ExpandAllNodes()
                CType(FindControl("lblPopTaskError"), Label).Text = ""
    
                'If a Goal has been edited, update Goal Menu
                If intIsGoal = 1 Then
                    DoListOutline.tvGoalMenu.DataBind()
                    DoListOutline.updGoalMenu.Update()
                    'sqlGoalList.DataBind()
                    FindControl("ddlPopTaskGoal").DataBind()
                    DoListOutline.cboAddApptmtProject.DataBind()
                End If
    
                'Update panel containing tvDoList
                'CType(DoListOutline.FindControl("updDoList"), UpdatePanel).Update()
                Dim upd = CType(cphMain.FindControl("updDoList"), UpdatePanel)
                upd.Update()
    
            Else
                CType(FindControl("lblPopTaskError"), Label).Text = "An error occurred.  Unable to update task."
    
            End If
    
        End Sub
    

    Wednesday, April 29, 2020 2:02 AM
  • User1535942433 posted

    Hi Sheldon Penner,

    I need to also find a way for the Master page to determine which page is currently its Content page, since the panel to be updated has a different id in each case.  (I could, I suppose, give all these update panels the same name, but that strikes me as the kind of shortcut liable to bite me on the butt some time in the future.)  

    Accroding to your description,I don't understand your requirments clearly.What means that master page determine which page is currently its Content page?

    The code above does not throw any errors, but it does not update the UpdatePanel.  (cphMain is the id of the ContentPlaceHolder on the master page that contains the update panel.)

    How do you show modalpopup?If you alter the Label text at code behind but calling show() at client side, it may not be successful.I suggest you may change the text by using javascript's innerText method and then show up the popup.

    Is there a better way to share popups among several pages?

    I suggest you could create a a user control with your modal popup. You then can expose the show function publicly from your user control or launch it via javascript when you need to from any form that has the user control.

    Besides,I suggest you could post your full codes of front pages to us.It will help us to solve your problems.

    Best regards,

    Yijing Sun

    Wednesday, April 29, 2020 9:36 AM
  • User1120190316 posted

    Success!

    Since last posting here, I have read a couple of articles that recommend creating an Event to run when the data is saved, i.e., after the stored procedure uspTaskPopup_Save has successfully run.   Then the panel on the content page can be updated by the event handler which would live on the content page.  Here is the relevant code:

    The following codebehind on the master page runs when the button on the popup form is clicked:

        Protected Sub btnPopTask_Save_Click(sender As Object, e As EventArgs) Handles btnPopTask_Save.Click
    
            'Get data from popup form pnlTask_Pop
            Dim strTaskID As String = CType(FindControl("hidPopTaskID"), HiddenField).Value.ToString
            If Not IsNumeric(strTaskID) Then strTaskID = "0"
            Dim strPostTaskID As String = CType(FindControl("hidPopPostTaskID"), HiddenField).Value.ToString
            If Not IsNumeric(strPostTaskID) Then strPostTaskID = "0"
    
    
            Dim strOwnerID As String = Session("OwnerID").ToString
            Dim strTaskName As String = CType(FindControl("txtPopTaskName"), TextBox).Text.Replace("'", "''")
            Dim strDisplayDate As String = CType(FindControl("txtPopTaskDisplayDate"), TextBox).Text
            Dim strListDate As String = CType(FindControl("hidPopTaskListDate"), HiddenField).Value.ToString
            Dim strDeadline As String = CType(FindControl("txtPopTaskDeadline"), TextBox).Text
            Dim bDone As Boolean = IsDate(CType(FindControl("txtPopTaskDateDone"), TextBox).Text)
            Dim strTaskNotes As String = CType(FindControl("txtPopTaskNotes"), TextBox).Text.Replace("'", "''")
            Dim strDateDone As String = CType(FindControl("txtPopTaskDateDone"), TextBox).Text
    
            Dim strGoalID As String = CType(FindControl("ddlPopTaskGoal"), DropDownList).SelectedValue.ToString
            Dim strGoalName As String = CType(FindControl("ddlPopTaskGoal"), DropDownList).SelectedItem.Text
            Dim intHighPriority As Integer = IIf(CType(FindControl("chkHighPriority"), CheckBox).Checked = True, 1, 0)
            Dim intIsGoal As Integer = IIf(CType(FindControl("chkIsGoal"), CheckBox).Checked = True, 1, 0)
            Dim intInactive As Integer = IIf(CType(FindControl("chkInactive"), CheckBox).Checked = True, 1, 0)
    
            'Update database
            Dim strSQL As String = "execute dbo.uspTaskPopup_Save " & _
                                    strTaskID & _
                                    ", " & strOwnerID & _
                                    ", '" & strTaskName & _
                                    "', '" & strDisplayDate & _
                                    "', '" & strDeadline & _
                                    "', " & strPostTaskID & _
                                    ", " & intHighPriority.ToString & _
                                    ", '" & strTaskNotes.Replace("<br />", vbCrLf) & _
                                    "', '" & strDateDone & _
                                    "', " & intIsGoal.ToString & _
                                    ", " & intInactive.ToString()
    
            'Stored procedure updates tblTask and returns TaskID of edited or added record
            Dim ReturnVal As Int32 = Convert.ToInt32(SqlHelper.ExecuteScalar(strSQL))
    
            'If ReturnVal indicates the sql succeeded, raise event that will update the content page
            If ReturnVal > 0 Then
    
                'Set error message to blank
                CType(FindControl("lblPopTaskError"), Label).Text = ""
    
                'Close form
                mpeTaskPop.Hide()
    
                'Let content page know about this
                RaiseEvent TaskSaved(Me, EventArgs.Empty)
    
            Else
                CType(FindControl("lblPopTaskError"), Label).Text = "An error occurred.  Unable to update task."
    
            End If
    
        End Sub
    

    As you can see, after it runs the stored procedure, it checks the value returned, and if the procedure ran successfully, it returns the ID number of the updated record.  If it was successful, the TaskSaved event is raised and the action switches to the event handler in the content file.

        Private Sub Master_TaskSaved(ByVal Sender As Object, ByVal e As EventArgs)
    
            GetSchedule(calFrom.SelectedDate, calTo.SelectedDate)
            tvDoList.ExpandAllNodes()
    
            'Update panel containing tvDoList
            updDoList.Update()
    
        End Sub

    GetSchedule() is a routine that revises the treeview tvDoList.

    I also added a line to the master page's code behind:

    Partial Class PPM
        Inherits System.Web.UI.MasterPage
    
        Public Event TaskSaved As EventHandler
    
        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            If Not IsPostBack Then
    
                With ScriptManager1
                    .RegisterAsyncPostBackControl(btnPopTask_Save)
                End With
    ...

    End Sub

    This creates the Event and then causes the btnPopTask_Save button to cause an asynch post-pack.

    Finally, I had to add a line of code to the content page's Sub Page_PreInit:

       Protected Sub Page_PreInit(sender As Object, e As EventArgs) Handles Me.PreInit
            AddHandler Master.TaskSaved, AddressOf Master_TaskSaved
    
        End Sub
    

    And now it runs.  Thank you for your help.  I hope the above is helpful to others.  I recommend the two articles that provided the information I needed.

    https://docs.microsoft.com/en-us/aspnet/web-forms/overview/older-versions-getting-started/master-pages/interacting-with-the-content-page-from-the-master-page-vb

    https://docs.microsoft.com/en-us/aspnet/web-forms/overview/older-versions-getting-started/master-pages/interacting-with-the-content-page-from-the-master-page-vb

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, April 29, 2020 3:12 PM