|
web
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Dynamically-created menus and mdi childrenoriginal topic somewhat so I thought I'd post again in hopes of getting input from others. I am creating a MenuStrip dynamically. For each ToolStripMenuItem, I'm adding an event handler so that the same routine gets called regardless of which menu item was clicked. All of this works great - my menu is being loaded properly and my routine gets called properly. Within the Tag property of each ToolStripMenuItem I store the name of a form that I want opened as an mdi child of my main form. I couldn't get this to work properly, so for testing purposes I've reduced my problem to the following scenario (which really has nothing to do with the Tag property or the fact that my form names are stored in variables): Behind my main form I created the following routine: Private Sub LoadForm() Dim frm As New frmTest With frm .MdiParent = Me .Left = 0 .Top = 0 .Show() End With End Sub I also added a button to my form and in the click event of the button, I call the above routine. In my routine that gets called when a menu item is clicked, I call the same LoadForm routine. If I click my button, frmTest loads as an mdi child as it should. If I click a menu item, my form does not get loaded (and yes, I've confirmed that the routine is getting called). Incidentally, if I comment out the line that says '.MdiParent = Me', my form will open as a normal Windows form. However, as soon as I uncomment out that line, my form will not load. I'm puzzled as to why such a simple thing would work when I click a button but not when I click a menu item. As an aside, I tried loading a menu with static menu items (instead of loading it dynamically), and everything worked fine - my mdi child form loaded properly. Any help would be greatly appreciated. Thanks, Steve hi Steve,
show the piece of code where you hook the handlers to the menuitems. Is it done within the MDIParent Load sub? -tom Hi Tom,
The following two routines are used to load my main menu. The first one is for my "main" items, and the second one gets called recursively to load all subitems. The first routine gets called during the load of my main form. Public Sub LoadMainMenu(ByVal prmMenu As MenuStrip) Dim con As SqlConnection Dim cmd As SqlCommand Dim drd As SqlDataReader Dim strSQL As String prmMenu.Items.Clear() con = New SqlConnection(THAGlobal.ConnectString) If IsECCI() Then strSQL = "SELECT MenuItemID, MenuItemName, MenuItemFormName, MenuItemFunctionName, MenuItemECCIOnlyFlag FROM MenuItems WHERE (MenuItemDisplayFlag=1) And (SubMenuOf Is Null) ORDER BY MenuItemDisplayOrder" Else strSQL = "SELECT MenuItemID, MenuItemName, MenuItemFormName, MenuItemFunctionName, MenuItemECCIOnlyFlag FROM MenuItems WHERE (MenuItemDisplayFlag=1) And (SubMenuOf Is Null) ORDER BY MenuItemDisplayOrder" End If cmd = New SqlCommand(strSQL) cmd.Connection = con Try con.Open() Catch ex As Exception Exit Sub End Try drd = cmd.ExecuteReader Try Do While drd.Read Dim tsi As New ToolStripMenuItem With tsi .Name = drd("MenuItemID") .Text = drd("MenuItemName") .Tag = vbNullString If drd("MenuItemFormName").ToString <> vbNullString Then .Tag = "F_" & drd("MenuItemFormName").ToString ElseIf drd("MenuItemFunctionName").ToString <> vbNullString Then .Tag = "U_" & drd("MenuItemFunctionName").ToString End If If drd("MenuItemECCIOnlyFlag") = 1 Then .ForeColor = Color.Red End If End With If tsi.Tag <> vbNullString Then AddHandler tsi.Click, AddressOf frmMain.MainMenuClicked End If Call LoadMenuItems(tsi) prmMenu.Items.Add(tsi) Loop drd.Close() Catch ex As Exception Finally con.Close() End Try End Sub Private Sub LoadMenuItems(ByVal prmParent As ToolStripMenuItem) Dim con As SqlConnection Dim cmd As SqlCommand Dim drd As SqlDataReader Dim strSQL As String con = New SqlConnection(THAGlobal.ConnectString) If IsECCI() Then strSQL = "SELECT MenuItemID, MenuItemName, MenuItemFormName, MenuItemFunctionName, MenuItemECCIOnlyFlag FROM MenuItems WHERE (MenuItemDisplayFlag=1) And (SubMenuOf = " & prmParent.Name & ") ORDER BY MenuItemDisplayOrder" Else strSQL = "SELECT MenuItemID, MenuItemName, MenuItemFormName, MenuItemFunctionName, MenuItemECCIOnlyFlag FROM MenuItems WHERE (MenuItemDisplayFlag=1) And (SubMenuOf = " & prmParent.Name & ") And (MenuItemECCIOnlyFlag = 0) ORDER BY MenuItemDisplayOrder" End If cmd = New SqlCommand(strSQL) cmd.Connection = con Try con.Open() Catch ex As Exception Exit Sub End Try drd = cmd.ExecuteReader Try Do While drd.Read Dim tsi As New ToolStripMenuItem With tsi .Name = drd("MenuItemID") .Text = drd("MenuItemName") If drd("MenuItemFormName").ToString <> vbNullString Then .Tag = "F_" & drd("MenuItemFormName").ToString ElseIf drd("MenuItemFunctionName").ToString <> vbNullString Then .Tag = "U_" & drd("MenuItemFunctionName").ToString End If If drd("MenuItemECCIOnlyFlag") = 1 Then .ForeColor = Color.Red End If End With If tsi.Tag <> vbNullString Then AddHandler tsi.Click, AddressOf frmMain.MainMenuClicked End If Call LoadMenuItems(tsi) prmParent.DropDownItems.Add(tsi) Loop drd.Close() Catch ex As Exception Finally con.Close() End Try End Sub You can see that I added an Event Handler to the Click event of my menu items (only the relevant ones). The Click event calls the following routine, which is located in my main form. Public Sub MainMenuClicked(ByVal sender As System.Object, ByVal e As System.EventArgs) Call LoadForm() End Sub LoadForm looks like this: Private Sub LoadForm() Dim frm As New frmParticipantSearch With frm .MdiParent = Me .Left = 0 .Top = 0 .Show() End With End Sub I also added a button with the following code: Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Call LoadForm() End Sub As I said before, if I click my button everthing works fine - my form loads as an mdi child. I've confirmed that my MainMenuClicked event is getting called when I click on any menu item that has a Tag assigned to it, as it should. If I step through the code at runtime using breakpoints, it'll call LoadForm and process every line with no errors, but I won't see my form. I removed it from here, but I previously added event handlers to the Load and FormClosed events of my test form just to see if the form was being loaded and immediately closed, but those events didn't fire (they were MsgBoxs that did fire when I clicked my button and subsequently closed my test form). The thing that gets me most is that if I comment out the line that makes my test form an mdi child, it works. I just can't assign my test form as an mdi child if it's being called via the menu. Also, I added a static menu and behind the click of one of the items I called LoadForm. Everything worked. Again, thanks for assistance. Steve Let's do a first attempt. Try replacing:
AddHandler tsi.Click, AddressOf frmMain.MainMenuClicked() with RemoveHandler tsi.Click, AddressOf frmMain.MainMenuClicked() AddHandler tsi.Click, AddressOf frmMain.MainMenuClicked() and let me know if anything changes... -t If you have not already done it, try putting a RemoveHandler before
*each* AddHandler, everywhere. As you describe the problem, it seems a reentrancy problem... -t (PS. Probably it would be easier if you reorganize some parts of code. In my experience it is usually not advisable to rely on the names of the controls in the code, as it makes difficult maintenance...) Yes, I put it before every AddHandler, everywhere.
As for your PS, I'm not sure what you mean unless you're referring to my use of frmMain. Can you elaborate a little (but not so much as to get away from the real issue here :) ) Thanks again. I'll be checking back in the morning. I'm done for the night. hi Steve,
I pasted you code in my editor connecting to an mdb I made on the fly. Actually it seems to be working. The child forms get open. One thing I am not clear. How come in : SubMenuOf = " & prmParent.Name & ") ORDER BY you do not need quotes as in: SubMenuOf = """ & prmParent.Name & """) ORDER BY did they get lost in the paste? -tom Actually, the Name of the Parent is an integer, as is the value of the
SubMenuOf field. I thought about changing this but haven't done so yet. I'm going to try creating a new application and pasting my code into it. Maybe something is just screwy with my app. I'll let you know what I find out. Thanks. Good. I am looking forward to knowing...
(PS: a recommendation: when you create the new app do enforce strict ON) Okay, I created the new app and it worked. I then figured out what the
differences were and figured out what caused it to not work in my original app, although I'm still not really sure why. In my first app, my main form is not the first form that opens. I open a Login form first and authenticate the user. If the user enters a valid username/password, I open the Main Form and close the Login form. In my project properties under the 'Application' tab I had changed my Startup Form to be my Login form and in the 'Shutdown mode' option I changed the default (When startup form closes) to 'When last form closes'. That seems to be what caused the problem because I am able to duplicate the problem in my second application. My second application loads my main form first, and duing the load of that form I open the Login form with ShowDialog. If the user authenticates properly I pass back to the Main Form a result of DialogResult.Yes - otherwise I pass back DialogBox.No. If the user does not authenticate properly (after 3 tries) I just close the main form and I'm done. Otherwise my main form continues to load and I load my main menu. This works fine. If you've got any idea as to why my first way doesn't load the mdi children properly, I'd be curious to know. I suspect my second approach is actually the better approach anyway, so I'm going to stick with it. Thanks a lot for the help. By the way, I noticed that if I open my mdi child it gets places at Left=0, Top=0 as I specified in my code. However, if I then close my child form and re-open it, it seems to be positioned lower and to the right, as if the first form were still opened and the two forms were being cascaded. My guess is that this is something fairly easy to fix and I haven't actually looked around for an answer yet, but I thought I'd ask in the hopes that you know offhand. Thanks again, Steve glad to hear that :)
-tommaso Private Sub LoadForm() Dim frm As New frmParticipantSearch With frm .MdiParent = Me .StartPosition = FormStartPosition.Manual '<-- .Location = New Point(0, 0) '.Left = 0 '.Top = 0 .Show() End With End Sub |
|||||||||||||||||||||||