WP7 - Cancelling ContextMenu click event propagation - silverlight

I'm having a problem when the Silverlight toolkit's ContextMenu is clicked while it is over a UIElement that has registered a Tap event GestureListener. The context menu click propagates to the underlying element and fires its tap event.
For instance, say I have a ListBox and each ListBoxItem within it has registered both a ContextMenu and a Tap GestureListener. Assume that clicking context menu item2 is supposed to take you to Page1.xaml, while tapping on any of ListBox items themselves is supposed to take you to Page2.xaml.
If I open the context menu on item1 in the ListBox, then context menu item2 is on top of ListBox item2. When I click on context menu item2 I get weird behavior where the app navigates to Page1.xaml and then immediately to Page2.xaml because the click event also triggered the Tap gesture for ListBox item2.
I've verified in the debugger that it is always the context menu that receives the click event first. How do I cancel the context menu item click's routed event propagation so it doesn't reach ListBox item2?
Thanks for your help!

You can get around the problem by doing the following:
In the context menu's Opened handler set LayoutRoot.IsHitTestVisible (LayoutRoot is the default name for the root UIElement) to false
In the context menu's Closed handler set LayoutRoot.IsHitTestVisible back to true

You could try adding a rectangle with a transparent background (important) over the effected area/page when showing the context menu.

I had a very similar issue, but I am using the ManipulationCompleted event as a "tap" detector as the object the ContentMenu applies to is a custom control.
LayoutRoot.IsHitTestVisible didn't work for me, perhaps because it does not apply to Manipulation events. However, it set me on the right path. I just implemented my own simple equivalent of it - I created a boolean variable bCancelManipulation in the page's scope.
In the ContentMenu's Opened event set it to True.
In the ContentMenu's Closed event set it to False.
In the ManipulationCompleted function, the first thing I do is check
if(bCancelManipulation==true) { return; }
It's kind of a hack, but it works great and is quite simple to code - it can easily be adapted to a Tap event too.

Related

Show Winforms Contextmenu over ChromiumWebBrowser

I'm working on a Winforms project that uses CefSharp as a Gui. For several reasons I would like to implement a custom context menu using the Winforms ContextMenu class; rendering the menu in Html or customizing the ChromiumWebBrowser's context menu (using CefSharp.IContextMenuHandler) are not an option.
The context menu it triggered by Javascript code that calls a method on a .net object I passed to RegisterAsyncJsObject; the default context menu is prevented using Javascript. I'm invoking the method call on the Gui thread, because the call over the "javascript bridge" to the registered object comes from a different thread.
My problem: when manually showing the Winforms context menu over the CefSharp.WinForms.ChromiumWebBrowser the context menu does not get the keyboard focus (e.g. selecting items with the arrow key doesn't work nor can I close the contextmenu using Esc); instead the keyboard focus remains with the ChromiumWebBrowser control. And, if I click on the ChromiumWebBrowser's control area the context menu doesn't close either. I can only close the context menu by selecting an item with the mouse or clicking on another control within the form (in which the ChromiumWebBrowser is contained) or somewhere completely else (e.g. desktop or another application).
If I trigger the context menu from elsewhere in my code - ultimately using the same method that calls myContextMenu.Show() - the context menu gets the keyboard focus as desired. But one problem still remains: it doesn't close when I click within the ChromiumWebBrowser control.
I haven't used IFocusHander, IContextMenuHandler, IKeyboardHandler - should I?
I'm using CEF 3.2454.1344.g2782fb8, Chromium 45.0.2454.101 and .net 4.5.1.
Unfortunately extracting demo code isn't reasonably possible.
Anyone any ideas?
EDIT1:
After reading the comments, I decided to describe the code flow more precisely:
When right clicking Javascript sends a message to the registered .net object, containing the mouse coordinates. The default context menu is prevented by setting preventDefault on the MouseEvent arguments of the ContextMenu event.
The registered .net object receives the messages and calls windowForm.Invoke(Sub() ... ), because the message is not received on the Main/Gui thread, but must be processed there for the context menu to appear correctly.
The contextmenu is created and assigned to the ContextMenuStrip property of the UserControl that contains the actual ChromiumWebBrowser control.
It is displayed using ContextMenuStrip.Show(location) method.
Issues:
The context menu has no keyboard-focus.
All mouse events appear to be "swallowed" by the ChromiumWebBrowser: clicking there does not close the context menu.
Opening the context menu identically except for using a different "trigger" works fine, except for the 2nd issue.
In the end the solution is simple; everything works as implemented and desired, if the following steps are added:
Before showing the context menu disable the UserControl with the ChromiumWebBrowser and set the focus to the owning form; something like this:
Private Sub showContextMenu(position As Point)
Me.ctrlCefBrowser.Enabled = False
Me.Focus()
myContextMenu.Show(position)
End Sub
That takes the focus away from the ChromiumWebBrowser, giving the context menu a chance to respond to the keyboard inputs. And also, by disabling the control, the mouse events are not "swallowed" anymore so clicking on the browser area causes the context menu to go away again.
Then, finally, add an event handler to the context menu to re-enable the browser control again:
Private Sub myContextMenu_Closed(sender As Object, e As ToolStripDropDownClosedEventArgs) Handles myContextMenu.Closed
Me.ctrlCefBrowser.Enabled = True
Me.ctrlCefBrowser.Focus()
End Sub
That did the trick for me, now I have a fully customizable Gdi context menu for my webbrowser control :o)
Note:
A similar problem arises when using other menus as well, e.g. in a main menu or tool bar: clicking on the ChromiumWebBrowser control will not close the menu (because the mouse event is also "swallowed"). The same solution can be applied: when opening a drop down menu deactivate (Enabled = False) the web browser control. And when it closes, reactivate it. For my menus I used a derived class (Inherits ToolStripMenuItem) that adds listeners to the according events. That takes care of the problem in a global and simple way.
EDIT:
The proposed solution above left the problem that the click on the disabled browser control closed the menu as intended, but got lost, i.e. the browser couldn't process it. My current workaround now is:
Do not disable the browser control.
Using the openening events of menu items and context menus, keep track of which menu is currently open.
When the browser receives the focus (obtainable by intercepting WndProc messages) close the opened menu.
Implementing the actual solution caused some headaches in the details, but maybe that helps someone along anyhow...

Strange issue - mouse click in popup is getting captured by control underneath

I'm displaying a Popup in response to a button click (popup.IsOpen = true;). The popup contains a ComboBox, and when I click an item in the combobox, one of the things the SelectionChanged event does is to hide the popup.
The Popup appears over a DataGrid that I also have on my page, and I'm finding that the mouse-click on the combobox is also being picked up by a MouseUp event that I've got on the DataGrid. Any idea what's going on?
The MouseUp Event has a routing strategy of type Bubbling. Events that use this type of strategy get passed up the chain to parent controls. Since the Popup is a child of the DataGrid, the event will "bubble" up to the DataGrid. If you would rather the event not bubble, you can try using PreviewMouseUp, which has a Tunneling routing strategy, and will "tunnel" down the chain to child controls. Here is a decent overview of Routing Strategies.
I've hit the same issue. Oddly, it doesn't happen when the code is run in the debugger - it only happens in the release version. It really seems to be a bug in WPF. Trying to catch the click and set the event to handled doesn't work.
My workaround is to, when the popup opens, to tell the control underneath to ignore the click.

How can I prevent events being fired on the Winform when I click on a WPF popup?

I have a wondows form which contains a WPF control as well. When I click on the control it brings up a WPF popup control with a listbox. The goal is, when I select an item on the listbox, the windows form will be repopulated accordingly and the popup should get closed. The current implementation with SelectionChanged on the listbox works fine.
Here is the problem. The popup is big and covers some portion of the winform which contains some links. Now, when I select an item on the listbox, the popup closes after doing necessary actions, but if there is a link just below the popup (on the winform) that is under the cursor (when you selected the item on the listbox), that link is also taking the click event.
Is there any way to prevent the links getting clicked when I click on the popup? I have to close the popup though.
I think I figured this out.
SelectionChanged gets executed when we press the mouse key down and before we lift it.(Mouse key up). The popup gets closed in SelectionChanged before we lift the Mouse key. So, when we leave the mouse key, the keyUp event actually gets fired for a link on the Winform as the popup has been closed by now.
I moved the logic from SelectionChanged to PreviewMouseUp and the popup stays till I leave the mouse key and therefore the links on the Winform do not get the event. Of course, I check whether the selection has been changed or not.

How to disable context menu in WPF?

I have two Menu items in a wpf context,
I bind them with command, how do I hide context menu when both items are not available, I mean when both commands cannot be executed?
Add an event handler for ContextMenuOpening event. Set Handled property in ContextMenuEventArgs object to true and the context menu will not open.

WPF composite Application - tab region - view not getting focus

I'm just starting to use the composite application libraries for WPF. In my shell I have a region in a tabcontrol that is used to display different types of views. I also have a toolbar with buttons hooked up to commands, for example save. The commands are bound in my views, and the views have the canExecute and execute methods.
The idea is that when i click a tab, my tool bar buttons should be enabled or disabled according to the methods in the view. Problem is when I switch tabs the view is not getting the focus and the canExecute for that view doesn't get called. The toolbar buttons remain connected to the commands in the previously selected view, and reminds that way until i actually click on the new view
I'm stumped right now on how to force the view to get the focus. I've tried looking at the tab's content when the tabs SelectionChanged and setting the focus there but its not making a difference. Any ideas?
Try listening for the View.Loaded event, then call View.focus() in the handler. Wpf will not accept focus requests before an element is initialized and loaded. Since the SelectionChanged event is raised before the view is loaded, the focus request will just be ignored. The loaded event is called each time the element is shown after being hidden.
See this blog post for more information on focus:
http://www.julmar.com/blog/mark/PermaLink,guid,6e4769e5-a0b3-47b2-a142-6dfefd0c028e.aspx

Resources