MDI, MenuStrips and Windows Forms 2.0

Working on an MDI app.  I wanted to have the main menu change based on the child window that's active.  Windows Forms provides a way to do this via menu merging.

 

Menu merging underwent some changes from WinForms 1.1 to WinForms 2.0.  A few tips:

 


  • set MergeIndex of child menu item to desired index in parent (0 is first index)
  • for each child menu item
  •   if something is already at the desired index then use merge action
  •      if merge action is insert then insert the child menu item above the item already there
  •      if merge action is append, put it after
  •      ...
  •    consider next child in light of new ordering

The last point bears explanation.  If the merge action is insert then the child item pushes down whatever was there.  That increases its new index.  So if you want the next child item to appear below the first child item in the merged menu then you will need to set its MergeIndex taking this into account.

e.g., child menu item1 has merge index of 2 and merge action of insert.

To stuff child menu item1 and 2 into the parent menu child menu item2 will need a merge index of 3.  This is the case because, after the first loop child menu item1 pushed the previous occupant into position 3.  So child menu item2 needs to push that occupant (in position 3) down.

C# Platform Invoke Interop tip

Visual Basic 6.0 includes a tool called "API Text Viewer" that automatically generates method prototypes for win32 api methods.  These are generated for visual basic so they can't be directly used in C# but converting from the VB syntax to the C# syntax is often easier than converting directly from the native prototype.

e.g., the native signature for GetUserObjectInformation() is:

BOOL GetUserObjectInformation(
HANDLE hObj,
int nIndex,
PVOID pvInfo,
DWORD nLength,
LPDWORD
lpnLengthNeeded
);





the VB prototype:






Public Declare Function GetUserObjectInformation Lib 
"user32" Alias "GetUserObjectInformationA" (ByVal hObj As Long, ByVal nIndex As
Long, pvInfo As Any, ByVal nLength As Long, lpnLengthNeeded As Long) As
Long








the C# prototype, at least for nIndex=2 (which gets the name of the object):







[DllImport("user32.dll")]

public static extern int
GetUserObjectInformaiton(int hObj, int nIndex, StringBuilder info, int nLength,
ref lengthNeeded)







A StringBuilder works here because when nIndex is 2 pvInfo will return a string.  Remember to initialize it with a max capacity equal to nLength (e.g., new StringBuilder(300, 300)).