How can I create a modal popup menu?

  • Thread starter Thread starter David Thielen
  • Start date Start date
D

David Thielen

Hi;

Due to design decisions taken long ago and a boatload of existing code, we
need to display a popup menu and get the user selection from that menu (which
can include clicking elsewhere to end the menu with no selection) and only
then, return the user's choice.

How can I do this? I've searched for an example but can't find any.

--
thanks - dave
david_at_windward_dot_net
http://www.windwardreports.com

Cubicle Wars - http://www.windwardreports.com/film.htm
 
To call ContextMenu.Show() you must pass it a parent Control. I am in a Word
AddIn so the parent of the popup is Word and I have an HWnd but it's not a
Control. How do I set the parent? It won't take a null.

1. You are right, you need a parent control. I have a vague recollection
about there being a way to wrap an hwnd in a .net object, but I don't recall
(and maybe I'm fooling myself). If you have the time, consider scouring the
..net documentation for ways and means to do this.

2. In the OP, you said you have a big code investment. How did your
problem arise? Did you convert to word scripting from something that was
already working in .net? This is more than just a curiosity - this is a .net
newsgroup, not a word newsgroup. Are you in the right house?

3. ContextMenuStrip supercedes ContextMenu. Maybe there is good news here
- I don't know, I haven't read about it.

4. Maybe you could provide some new word-ish way of interacting with the
user, and then map its output into a context menu setting thereby protecting
you investment.

5. Maybe you could create a transparent and/or small .net form whose sole
purpose is to be the parent of your context menu. To raise the menu, you
show the form. When the menu is dismissed, you close the form.
 
David Thielen said:
And...

To call ContextMenu.Show() you must pass it a parent Control. I am in a
Word
AddIn so the parent of the popup is Word and I have an HWnd but it's not a
Control. How do I set the parent? It won't take a null.

Try something like this. You'll need to work out what to do with the return
value.
[DllImport("user32")]

private static extern int TrackPopupMenu(IntPtr hMenu, int wFlags, int x,
int y, int nReserved, IntPtr hwnd, IntPtr lprc);

private const int TPM_RETURNCMD = 0x0100;



ContextMenu menu = new ContextMenu();

MenuItem mi = new MenuItem("A");

menu.MenuItems.Add(mi);

menu.MenuItems.Add(new MenuItem("B"));

menu.MenuItems.Add(new MenuItem("C"));

this.Text = TrackPopupMenu(menu.Handle, TPM_RETURNCMD, 0, 0, 0, this.Handle,
IntPtr.Zero).ToString();


Michael
 
Hello Dave,

Based on my understanding, you are looking for a method to show a custom
popup menu in Excel. As AMercer said, ContextMenuStrip might be a
resolution because it does not need a parent handle. Please have a try to
see if it fits your request. From the view of Excel, another possible
workaround is to customize the built-in popup menu when we right-click on a
worksheet cell. Here is an example:

public void OnConnection(object application,
Extensibility.ext_ConnectMode connectMode, object addInInst, ref
System.Array custom)
{
applicationObject =
(Excel.Application)application;
applicationObject.SheetBeforeRightClick += new
Excel.AppEvents_SheetBeforeRightClickEventHandler(applicationObject_SheetBef
oreRightClick);
addInInstance = addInInst;
}

void applicationObject_SheetBeforeRightClick(object Sh,
Microsoft.Office.Interop.Excel.Range Target, ref bool Cancel)
{
CommandBar cellbar = applicationObject.CommandBars["Cell"];
CommandBarButton button =
(CommandBarButton)cellbar.FindControl(MsoControlType.msoControlButton, 0,
"MYMENU", missing, missing);
if (button == null)
{
// add the button
button =
(CommandBarButton)cellbar.Controls.Add(MsoControlType.msoControlButton,
missing, missing, cellbar.Controls.Count + 1, true);
button.Caption = "My Menu";
button.BeginGroup = true;
button.Tag = "MYMENU";
button.Click += new
_CommandBarButtonEvents_ClickEventHandler(button_Click);
}
}

void button_Click(CommandBarButton Ctrl, ref bool CancelDefault)
{
MessageBox.Show("Test");
}

The example register the SheetBeforeRightClick event. In the event handler,
we check if the custom button has already been added to the popup menu. If
not, we add the button by calling CommandBar.Controls.Add method. After we
install the add-in, it shows a custom button "My Menu" at the bottom of
right-click popup menu, and shows a "Text" message box when we click on it.

If you have any other concern or need anything else, please feel free to
let me know.

Regards,
Jialiang Ge ([email protected], remove 'online.')
Microsoft Online Community Support

=================================================
When responding to posts, please "Reply to Group" via your newsreader
so that others may learn and benefit from your issue.
=================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Hi;

I can't use the Excel RMB menu because I need to pop this up, the user
doesn't.

Same problem with ContextMenuStrip but when I call Show(), nothing shows and
it returns instantly. All the sample show it being attached to a control as
the context menu - but I need to just pop up a free-floating menu and get
what is clicked.

Any other approaches?

--
thanks - dave
david_at_windward_dot_net
http://www.windwardreports.com

Cubicle Wars - http://www.windwardreports.com/film.htm




Jialiang Ge said:
Hello Dave,

Based on my understanding, you are looking for a method to show a custom
popup menu in Excel. As AMercer said, ContextMenuStrip might be a
resolution because it does not need a parent handle. Please have a try to
see if it fits your request. From the view of Excel, another possible
workaround is to customize the built-in popup menu when we right-click on a
worksheet cell. Here is an example:

public void OnConnection(object application,
Extensibility.ext_ConnectMode connectMode, object addInInst, ref
System.Array custom)
{
applicationObject =
(Excel.Application)application;
applicationObject.SheetBeforeRightClick += new
Excel.AppEvents_SheetBeforeRightClickEventHandler(applicationObject_SheetBef
oreRightClick);
addInInstance = addInInst;
}

void applicationObject_SheetBeforeRightClick(object Sh,
Microsoft.Office.Interop.Excel.Range Target, ref bool Cancel)
{
CommandBar cellbar = applicationObject.CommandBars["Cell"];
CommandBarButton button =
(CommandBarButton)cellbar.FindControl(MsoControlType.msoControlButton, 0,
"MYMENU", missing, missing);
if (button == null)
{
// add the button
button =
(CommandBarButton)cellbar.Controls.Add(MsoControlType.msoControlButton,
missing, missing, cellbar.Controls.Count + 1, true);
button.Caption = "My Menu";
button.BeginGroup = true;
button.Tag = "MYMENU";
button.Click += new
_CommandBarButtonEvents_ClickEventHandler(button_Click);
}
}

void button_Click(CommandBarButton Ctrl, ref bool CancelDefault)
{
MessageBox.Show("Test");
}

The example register the SheetBeforeRightClick event. In the event handler,
we check if the custom button has already been added to the popup menu. If
not, we add the button by calling CommandBar.Controls.Add method. After we
install the add-in, it shows a custom button "My Menu" at the bottom of
right-click popup menu, and shows a "Text" message box when we click on it.

If you have any other concern or need anything else, please feel free to
let me know.

Regards,
Jialiang Ge ([email protected], remove 'online.')
Microsoft Online Community Support

=================================================
When responding to posts, please "Reply to Group" via your newsreader
so that others may learn and benefit from your issue.
=================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Hello Dave,

I did a test with ContextMenuStrip:

I expected a custom Contextmenu to show when I right clicked on a worksheet
cell. So I needed to register the Excel SheetBeforeRightClick event. In its
event handler, firstly, I disabled the built-in context menu, then I showed
a context menu stip at the current mouse position. Here is the code:

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetCursorPos(out System.Drawing.Point lpPoint);

void applicationObject_SheetBeforeRightClick(object Sh,
Microsoft.Office.Interop.Excel.Range Target, ref bool Cancel)
{
CommandBar cellbar = applicationObject.CommandBars["Cell"];
cellbar.Enabled = false; // disable the built-in context menu.
// show the context menu strip
ContextMenuStrip menu = new ContextMenuStrip();
menu.Items.Add("just for test");
// get the current mouse position
System.Drawing.Point mouseP;
GetCursorPos(out mouseP);
menu.Show(mouseP); // show the context menu strip at the
current mouse position.
}

public void OnConnection(object application,
Extensibility.ext_ConnectMode connectMode, object addInInst, ref
System.Array custom)
{
applicationObject = (Excel.Application)application;
applicationObject.SheetBeforeRightClick += new
Excel.AppEvents_SheetBeforeRightClickEventHandler(applicationObject_SheetBef
oreRightClick);
addInInstance = addInInst;
}

The code above worked well and did not reproduce the issue: "nothing shows
and it returns instantly". Would you have a try and let me know the result?

Have a nice day!

Regards,
Jialiang Ge ([email protected], remove 'online.')
Microsoft Online Community Support

=================================================
When responding to posts, please "Reply to Group" via your newsreader
so that others may learn and benefit from your issue.
=================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
David Thielen said:
Hi;

I can't use the Excel RMB menu because I need to pop this up, the user
doesn't.

Same problem with ContextMenuStrip but when I call Show(), nothing shows
and
it returns instantly. All the sample show it being attached to a control
as
the context menu - but I need to just pop up a free-floating menu and get
what is clicked.

Any other approaches?

Did you try the suggestion in my post? Just in case it's missing here it is
again:

Michael



Try something like this. You'll need to work out what to do with the return
value.
[DllImport("user32")]

private static extern int TrackPopupMenu(IntPtr hMenu, int wFlags, int x,
int y, int nReserved, IntPtr hwnd, IntPtr lprc);

private const int TPM_RETURNCMD = 0x0100;



ContextMenu menu = new ContextMenu();

MenuItem mi = new MenuItem("A");

menu.MenuItems.Add(mi);

menu.MenuItems.Add(new MenuItem("B"));

menu.MenuItems.Add(new MenuItem("C"));

this.Text = TrackPopupMenu(menu.Handle, TPM_RETURNCMD, 0, 0, 0, this.Handle,
IntPtr.Zero).ToString();
 
Ok, figured out what is happening. The call to Show() does start the menu but
Show returns immediately and as I am then in my debugger, the popup menu is
closes before it is fully drawn.

So yes, it will display the menu. But Show() returns immediately and
therefore I can't use it as I need it to be modal and not return until the
user has made a selection.

--
thanks - dave
david_at_windward_dot_net
http://www.windwardreports.com

Cubicle Wars - http://www.windwardreports.com/film.htm
 
Sorry, yes. Same problem, it's not modal.

--
thanks - dave
david_at_windward_dot_net
http://www.windwardreports.com

Cubicle Wars - http://www.windwardreports.com/film.htm




Michael C said:
David Thielen said:
Hi;

I can't use the Excel RMB menu because I need to pop this up, the user
doesn't.

Same problem with ContextMenuStrip but when I call Show(), nothing shows
and
it returns instantly. All the sample show it being attached to a control
as
the context menu - but I need to just pop up a free-floating menu and get
what is clicked.

Any other approaches?

Did you try the suggestion in my post? Just in case it's missing here it is
again:

Michael



Try something like this. You'll need to work out what to do with the return
value.
[DllImport("user32")]

private static extern int TrackPopupMenu(IntPtr hMenu, int wFlags, int x,
int y, int nReserved, IntPtr hwnd, IntPtr lprc);

private const int TPM_RETURNCMD = 0x0100;



ContextMenu menu = new ContextMenu();

MenuItem mi = new MenuItem("A");

menu.MenuItems.Add(mi);

menu.MenuItems.Add(new MenuItem("B"));

menu.MenuItems.Add(new MenuItem("C"));

this.Text = TrackPopupMenu(menu.Handle, TPM_RETURNCMD, 0, 0, 0, this.Handle,
IntPtr.Zero).ToString();
 
David Thielen said:
Sorry, yes. Same problem, it's not modal.

What do you mean by modal? That the function doesn't return until after the
user selects a menu? This is how it behaved on my machine. Perhaps something
is killing the menu the moment it is shown?

Michael
 
Apologies to the group for this off-topic message.

Michael,

You didn't come back to the vb.general.discussion newsgroup yesterday (or
today yet either)... I just wanted to tell you that I posted a follow-up
function for you that, I think, is closer to what you wanted than my first
function (which you said you were going to test out). I'm hoping I caught
you earlier enough in order to bring you attention to my posting over there.
Make sure you look at my responses to the message posted by Schmidt as it
contains a minor correction for a problem he found.

Rick
 
Rick Rothstein (MVP - VB) said:
Apologies to the group for this off-topic message.

Michael,

You didn't come back to the vb.general.discussion newsgroup yesterday (or
today yet either)... I just wanted to tell you that I posted a follow-up
function for you that, I think, is closer to what you wanted than my first
function (which you said you were going to test out). I'm hoping I caught
you earlier enough in order to bring you attention to my posting over
there. Make sure you look at my responses to the message posted by Schmidt
as it contains a minor correction for a problem he found.

Sorry for my slackness. I will have a look now.

Michael
 
Back
Top