Passing events from the menu to a control

M

michael sorens

I created a user control that handles certain keystrokes, e.g. Ctrl-C for
cut, Ctrl-V for paste, plus other more specialized keystrokes. I want to list
these in the menubar like any other menu items. Once I assign a Shortcut Key
to the menu item, that menu sees the event before the control, as one would
expect. The question is, then, inside the menu item handler what code do I
need to pass on the keystroke to a control? This is slightly complicated by
the fact that the keystroke could go to any one of several controls,
depending on which is active. I have not been successfully in web searches on
this topic so far.
Environment: .Net 3.0, VS2005, C#.
 
L

Linda Liu[MSFT]

Hi Michael,

Based on my understanding, you have a UserControl that handles certain
short keys and you'd like to set these keys as the shortcut keys of some
menu items. The problem is that you don't know what code you should write
in the menu item Click event handler because the key stroke could go to any
one of several controls, depending on which is ative. If I'm off base,
please feel free to let me know.

Firstly, I don't think it makes any difference after you assign the
shortcut keys of the menu items. You can still use the ActiveControl
propetry of the form to determine which control in the form is active
currently.

I will illustrate this with an example. It requires you to add a MenuStrip
with a menu item to a form. The menu item has a shortcut key of Ctrl+W. It
also requires you to add two TextBoxes onto the form. In the menu item's
Click event handler, write down the following code:

private void toolStripMenuItem1_Click(object sender, EventArgs e)
{
TextBox txtbox = this.ActiveControl as TextBox;
if (txtbox != null)
{
txtbox.Copy();
}
}

Build the project and run the application. Type some text into one of the
two TextBoxes and select some text in it. Whether you click the menu item
on the form or press Ctrl+W, the selected text is copied to the Clipboard.

Hope this helps.
If you have any question, please feel free to let me know.

Sincerely,
Linda Liu
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
M

michael sorens

Thanks for the suggestions, but that is not quite what I need. Your code
sample uses the approach of explicitly calling methods to do specific
actions. What I need to do is different--I just want the menu item handler to
"get out of the way". By that, I mean I want it to pass on the keystroke
event so that whatever would have happened to the keystroke (if the menu
handler did not intercept it) happens.
To put this another way, if the menu item event provided a KeyPressEventArgs
argument instead of an EventArgs argument, the menu item handler would simply
set the Handled property to false, allowing the KeyPress event to "pass
through".
 
L

Linda Liu[MSFT]

Hi Michael,

Thank you for your reply!

We can call the SendKeys.Send method to send keystrokes to the active
application. In your scenario, you can call the SendKeys.Send method to
send the shortcut key of the menu item to the application so as to "pass"
on the key stroke event.

For example, we use Ctrl+O as the shortcut key of a menu item. In the Click
event handler of this menu item, add the following line of code to send
Ctrl+O to the application.

private void toolStripMenuItem1_Click(object sender, EventArgs e)
{
SendKeys.Send("^o");
}

For more information on the SendKeys.Send method, you may refer to the
following MSDN document:

http://msdn2.microsoft.com/en-us/library/system.windows.forms.sendkeys.send.
aspx

Hope this helps.
If you have any question, please feel free to let me know.

Sincerely,
Linda Liu
Microsoft Online Community Support
 
M

michael sorens

What you suggest will simply cause an infinite loop--it will return to the
exact same handler, unless you have some trick to do otherwise that you do
not mention. (And besides that, I do not believe that invoking what is
essentially a debugging aid for routine code would really be considered a
"best practice" for this scenario.)
 
P

Peter Duniho

What you suggest will simply cause an infinite loop--it will return to
the
exact same handler, unless you have some trick to do otherwise that you
do
not mention. (And besides that, I do not believe that invoking what is
essentially a debugging aid for routine code would really be considered a
"best practice" for this scenario.)

Here's the thing: there is no public method in Control that will allow you
to just pass along the data from a key event.

You mentioned in a previous post that you'd like to be able to just set a
"Handled" property to false, but this only works when you're in the same
chain of event handlers for an event. You're trying to translate an event
that occurs in one object to be handled by event handling in a different
object. At least, that's how your posts read.

Given what you've written so far, I think Linda's replies are quite
appropriate. Her first suggestion is in fact what I would have suggested
given your question, and her second suggestion seems like the most obvious
alternative given your refusal to just use the simple solution of calling
methods directly.

It's difficult for me, reading your question, to know _exactly_ what it is
you're trying to do. It's possible that you're not getting answers that
you find useful because you haven't really described your question very
well.

As an example of the vagueness of your question: we do not even know which
menu class you're using. I mean, I suppose we can assume you're dealing
with a ToolStrip menu, with ToolStripMenuItem instances. But you haven't
said that explicitly.

As another example: you've provided no simple code sample to illustrate
how your code works now, nor to illustrate what sort of architectural
design you'd like to implement. In the latter case, you wouldn't
necessarily need to provide working code (obviously :) ). Just code that
_looks_ like what you think the final solution should look like.

It's _possible_ that your question could be answered by suggesting that
you subclass ToolStripMenuItem and override a method like ProcessCmdKey()
or ProcessDialogKey(), or by suggesting that you set up some sort of
"keystroke received" event that the active control can subscribe to and
which you raise in response to receiving a keystroke in your menu.

But with such a vague question, it's going to be very hard to say for sure.

Pete
 
M

michael sorens

I want to say first, Pete, that I appreciate you taking the time to put down
your thoughts so thoroughly. My comments:

(1) My rejection of the "simple" solution was not on a whim; I do not have
exposed methods to call needed by that solution (which I should have stated).

(2) I maintain that the SendKey suggestion is an infinite loop--yet you say
this is "appropriate"; please explain how.

(3) Regarding your comment "You're trying to translate an event
that occurs in one object to be handled by event handling in a different
object." That was present, in fact, for precisely the reason of
disambiguating what I wanted. I was giving a related example--note that I
said "IF it provided ...". (Sounds like I am damned if I do, damned if I
don't :)

(4) Yes, I am referring to ToolStripMenuItems. I was not aware there were
other types, a fact reinforced by Linda's use of it in both examples.

(5) As for example code I cannot offer much beyond what Linda has already
provided twice:
private void toolStripMenuItem1_Click(object sender, EventArgs e)
{
// This menu command needs to pass the event--or perhaps
// generate a different event--so that the approrpriate
// event handler in a custom user control will act on the user's cmd.
}
For another example, consider the ordinary TextBox. It supports a variety of
keystrokes: cut, copy, paste, home, end, select-all, etc. I just want to add
those types of keys to a menu in the menu bar so that they are enumerated
along with all the menu commands that I am providing explicit implementation
for. It sounds like the only simple way to do this is from Linda's first
suggestion, i.e. call the specific methods.

Anyway, thanks for keeping me on my toes.
 
P

Peter Duniho

I want to say first, Pete, that I appreciate you taking the time to put
down
your thoughts so thoroughly. My comments:

(1) My rejection of the "simple" solution was not on a whim; I do not
have
exposed methods to call needed by that solution (which I should have
stated).

Whim or not, you did reject it. It may be for good reason, but that
doesn't change the desirability of using that solution. Just the
feasibility.
(2) I maintain that the SendKey suggestion is an infinite loop--yet you
say
this is "appropriate"; please explain how.

I don't see an infinite loop. Presumably the Click handler that Linda
posted resides in the Control that should receive the keyboard input, not
the ToolStripMenuItem. So, unless the Control upon receiving the keyboard
input then turns around and somehow raises a Click event in the
ToolStripMenuItem, where's the infinite loop?

Does your Control do that?
(3) Regarding your comment "You're trying to translate an event
that occurs in one object to be handled by event handling in a different
object." That was present, in fact, for precisely the reason of
disambiguating what I wanted. I was giving a related example--note that I
said "IF it provided ...". (Sounds like I am damned if I do, damned if I
don't :)

Well, that's fine. It's not how I read that post though. It's not just a
matter of having the event use a different EventArgs class. There's just
not even that event mechanism. It wasn't clear from your post that was
understood.
(4) Yes, I am referring to ToolStripMenuItems. I was not aware there were
other types, a fact reinforced by Linda's use of it in both examples.

ToolsStripMenuItem is the most common, but there are legacy classes that
you could have been using instead. In any case, you should always be
specific, even if in theory there are no other alternatives.
(5) As for example code I cannot offer much beyond what Linda has already
provided twice:
private void toolStripMenuItem1_Click(object sender, EventArgs e)
{
// This menu command needs to pass the event--or perhaps
// generate a different event--so that the approrpriate
// event handler in a custom user control will act on the user's cmd.
}

Well, first...those are Linda's examples, both of which you said were
inappropriate. How are we supposed to know that those actually do serve
as examples of what you're trying to do?

Secondly, those are hardly complete enough to really understand the
issue. They don't tell us anything about the Control classes you're
trying to interface with, or about how you'd prefer them to work.

Based on the code you posted above, either of Linda's suggestions would
work fine. Since you say they don't work fine, obviously the above
example is not nearly specific enough to provide useful advice to you.
You need to provide an example that is at least complete enough for people
to understand why the simple example's Linda's offered don't work.
For another example, consider the ordinary TextBox. It supports a
variety of
keystrokes: cut, copy, paste, home, end, select-all, etc. I just want to
add
those types of keys to a menu in the menu bar so that they are enumerated
along with all the menu commands that I am providing explicit
implementation
for. It sounds like the only simple way to do this is from Linda's first
suggestion, i.e. call the specific methods.

Well, the TextBox class has all of those specific methods (well, cut,
copy, paste, home, end, and select-all...I don't know what's left in
"etc." so I can't comment on that). But you wrote "I do not have exposed
methods to call needed by that solution".

So what's really the problem?
Anyway, thanks for keeping me on my toes.

You're welcome. :)

Pete
 
M

michael sorens

Regarding the infinite loop debate, you state "Presumably the Click handler
that Linda posted resides in the Control that should receive the keyboard
input, not
the ToolStripMenuItem." But no, Linda's handler is in the menu item.
Furthermore:
(a) If the handler is in the control, how is it supposed to get the event,
since the menu got it first?
(b) But say the control does get the event--then why would I need the click
handler? That is the whole point, to get the event to the control.

One of us, I think, is missing some assumption here since this issue is in
dispute; but I am not sure if it is you or me :)

In any case, it is not terribly crucial, as I think I have gained what I am
able from this thread.

Thanks for all the input.
 
P

Peter Duniho

Regarding the infinite loop debate, you state "Presumably the Click
handler
that Linda posted resides in the Control that should receive the
keyboard input, not
the ToolStripMenuItem." But no, Linda's handler is in the menu item.

Why do you say that? Nothing in Linda's post says that the handler "is in
the menu item", and it flies in the face of logic that it would be.

If for no other reason than that if it were, there's the possibility of an
infinite loop whereas if it's in the control, such a problem is avoided.
Also note that you specifically said you wanted to send the key to the
control...since her code does not qualify a specific control in the call
to the SendKeys() method, it stands to reason that the method is contained
within the control class that should receive the key input.

Why do you insist on believing that she posted useless code, rather than
accepting the possibility that maybe you misunderstand the code?
Furthermore:
(a) If the handler is in the control, how is it supposed to get the
event,
since the menu got it first?

Huh? A handler for any event can be anywhere in any class. It "gets the
event" by subscribing to the event. When the event is raised, it gets the
event.

Whether the menu "got it first" or not is irrelevant. There's not even
any reason to believe that the menu has a handler subscribed to the
event. The ToolStripMenuItem class itself is unlikely to have subscribed
to the event, so unless you've sub-classed the class and written your own
event handler which you've subscribed to the event, the menu would not in
fact have a handler subscribed to the event.
(b) But say the control does get the event--then why would I need the
click
handler? That is the whole point, to get the event to the control.

Well, it is in fact hard to understand what your problem is. I don't in
fact understand why you wouldn't just subscribe an event handler in the
control to the menu's event. But since you prefer to complain about the
answers given rather than elaborate on what the actual problem is, you
continue to apparently not receive the help you desire.
One of us, I think, is missing some assumption here since this issue is
in
dispute; but I am not sure if it is you or me :)

I am sure it is you.
In any case, it is not terribly crucial, as I think I have gained what I
am
able from this thread.

Does that mean that your problem is solved? If so, how is it solved?

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top