How can I tell when the default textbox context menu is about to open (before it opens) or after it has closed (not before, after)? The ContextMenuOpening and ContextMenuClosing events don't seem to fire when I'm using the standard, built-in menu. I'm guessing I could simply recreate the menu and populate it with standard commands, but that does seem to be a bit overkill.
The reason for this specifically, is I have a templated control that has a textbox swapped in when in 'Edit' mode. That control automatically drops out of edit mode when the textbox loses focus. Problem is when the context menu pops up, the textbox loses focus, and thus it drops out of edit mode, and the context menu disappears instantly.
What I want to do is just before the context menu opens, set a flag to short-circuit LostFocus event code on the textbox. Then after the context menu closes, I need to clear that flag but I also need to detect if the control that now has the focus is still the textbox, and if not, then process the code as if it did lose focus. (Alternately I could test an event prior to it closing if I knew which control will have the focus once it does close. It would achieve the same effect.)
This is needed to handle the specific case if someone shows the context menu (and as such the textbox technically doesn't have focus anymore) but then clicks elsewhere in the UI which dismisses the context menu, because I then need to detect that the textbox has in fact lost focus and as such the control should drop out of edit mode. But if the user dismisses the context menu by clicking back in the textbox, then I don't want that LostFocus event to fire.
Make sense?
M
UPDATE: Technically this question wasn't answered although I marked it as such since the responders did help me solve my problem. But as for the actual question here, it looks like the answer is 'You can't'.
The good news is since the default textbox context menu is just three standard items, it's easy to duplicate by adding this to the resources somewhere...
<ContextMenu x:Key="DefaultTextBoxContextMenu">
<MenuItem Command="ApplicationCommands.Cut" />
<MenuItem Command="ApplicationCommands.Copy" />
<MenuItem Command="ApplicationCommands.Paste" />
</ContextMenu>
...and attach it like this...
<TextBox x:Name="EditTextBox"
ContextMenu="{StaticResource DefaultTextBoxContextMenu}"
ContextMenuOpening="EditTextBox_ContextMenuOpening"
ContextMenuClosing="EditTextBox_ContextMenuClosing" />
...then your eventing works as you would expect. Still odd if you ask me, but a trivial work-around anyway so I won't complain.
M
There are several scenarios for handling the ContextMenuOpening event: Adjusting the menu items before display. Replacing the entire menu before display. Completely suppressing any existing context menu and displaying no context menu.
A context menu (also know as a contextual menu, shortcut menu or pop-up menu) is the menu that appears when you right-click and offers a set of choices that are available for, or in context of, whatever it was you clicked. The available choices are usually actions specifically related to the selected object.
When the textbox's context menu opens the textbox loses keyboard focus, but retains logical focus. In other words, its LostKeyboardFocus event will fire but its LostFocus event will not. The textbox's IsFocused property remains true when the context menu is open. Based on your description of the problem, you should be able to rely on logical focus to determine when to end "edit mode" in your control.
By default a TextBox
still reports true for IsFocused
while the default context menu is open but reports false for IsKeyboardFocused
. That is to say, LostFocus
is not raised on the TextBox
when the context menu is opened but will be raised if the context menu is closed by selecting some other control. This sounds like precisely the behavior you are looking for.
You can show this default behavior with a small test program:
<Grid>
<StackPanel>
<TextBox Text="Some text one"
GotFocus="TextBox_GotFocus"
LostFocus="TextBox_LostFocus"/>
<TextBox Text="Some text two"/>
</StackPanel>
</Grid>
and the code-behind:
private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
Debug.WriteLine("GotFocus");
}
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
Debug.WriteLine("LostFocus");
}
If you are not getting this default behavior in the context of your larger application, then there might be a focus scope issue interfering.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With