Invoke a ContextMenu to open
I need to do something like Google Maps does (but in WPF
):
- when
RightClick
on the map I have a ContextMenu. - when
RightDoubleClicking
I have the UnZoom action.
So, apparently, this is a little difficult in WPF... After struggling and searching a lot, read people that compains that "we can't predict the future" (I ask myself how does Google predict it), I decided to "wait" SystemInformation.DoubleClickTime and only then display a contextMenu.
Surely, this is not ideal, even human-observable, but I don't know other method.
So, the problem that I have with the following code is (I have a custom Canvas):
ContextMenuEventArgs lastContextMenuEventArgs开发者_JS百科 = null;
bool? lastContextMenuEventArgsHandled = null;
protected override void OnContextMenuOpening(ContextMenuEventArgs e)
{
lastContextMenuEventArgs = e;
lastContextMenuEventArgsHandled = e.Handled;
e.Handled = true;
//base.OnContextMenuOpening(e);
}
bool rightMouseClickedOnce = false;
protected override void OnPreviewMouseRightButtonUp(MouseButtonEventArgs e)
{
//base.OnPreviewMouseRightButtonUp(e);
Console.WriteLine(">>>>>>>>>>> OnPreviewMouseRightButtonUp");
if (!rightMouseClickedOnce)
{
rightMouseClickedOnce = true;
Thread thread = new Thread(
new System.Threading.ThreadStart(
delegate()
{
Thread.Sleep(System.Windows.Forms.SystemInformation.DoubleClickTime);
this.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Background,
new Action(
delegate()
{
if (rightMouseClickedOnce)
{
Console.WriteLine(">>>>>>>>>>> Right Click");
rightMouseClickedOnce = false;
base.OnPreviewMouseRightButtonUp(e);
if (lastContextMenuEventArgsHandled.HasValue)
{
Console.WriteLine(">>>>>>>>>>> lastContextMenuEventArgsHandled");
lastContextMenuEventArgs.Handled = lastContextMenuEventArgsHandled.Value;
base.OnContextMenuOpening(lastContextMenuEventArgs);
lastContextMenuEventArgsHandled = null;
}
//if (this.ContextMenu != null)
//{
// this.ContextMenu.PlacementTarget = this;
// this.ContextMenu.IsOpen = true;
//}
}
}
));
}
));
thread.Start();
}
else if (rightMouseClickedOnce)
{
Console.WriteLine(">>>>>>>>>>> Right Double Click");
rightMouseClickedOnce = false;
base.OnPreviewMouseRightButtonUp(e);
this.OnMouseRightDoubleClick(e);
}
}
Everything works great but a little problem: base.OnContextMenuOpening(lastContextMenuEventArgs);
does not seem to work...
I set before
if (this.ContextMenu != null)
{
this.ContextMenu.PlacementTarget = this;
this.ContextMenu.IsOpen = true;
}
and that worked, but finally this blocks child contextMenu elements from opening, and open always the parent (canvas) contextMenu.
Can I just invoke the contextMenu event?
I don't know much about WPF, but can you show the menu, say, a pixel away from the cursor and see if the user right-clicks again in the same spot and in the system double click time? I've used a similar technique once in a game and it performed nice enough.
A menu "fade in" (optionally, out, too) animation could make it even better.
精彩评论