我有以下WPF控件,它应该表现得像,例如GoogleMaps会这样做(放大左键双击,右键双击取消缩放):
<Grid>
<ScrollViewer x:Name="scrollViewer">
<Canvas x:Name="myCanvas"/>
</ScrollViewer>
</Grid>
还有一些代码:
void OnScrollViewerPreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
//this.myCanvas.ContextMenu = null;
if (e.OriginalSource is Canvas)
{
// zoom on left doubleClick
if (e.ChangedButton == MouseButton.Left)
{
ZoomOnMouseOnce();
} // UNzoom on right doubleClick
else if (e.ChangedButton == MouseButton.Right)
{
UnzoomOnMouseOnce();
}
e.Handled = true;
}
}
问题是当myCanvas有ContextMenu时,UnZoom方法不起作用,因为在ScrollViewer上不再捕获DoubleClick事件......
设置this.myCanvas.ContextMenu = null;
可以解决问题,但有没有办法绕过这个?...
答案 0 :(得分:1)
<强>更新强>
上传的小样本项目展示了这种效果。
http://www.mediafire.com/?du2jr18khx8ooy9
我为此尝试了一些不同的方法,我发现最接近的事情是将ContextMenu的HorizontalOffset偏移1。这允许在ContextMenu打开时右键双击。由于ScrollViewer仅收到第一次点击,因此在ContextMenu未打开时仍然无效。
您可以通过使用第一次右键单击的计时代码解决此问题,如果在线程用完之前发生另一次右键单击,则使用SendInput模拟另一次右键单击。虽然它可能不那么漂亮,但我完成了工作。
<Canvas ...>
<Canvas.ContextMenu>
<ContextMenu Placement="RelativePoint" HorizontalOffset="1">
<MenuItem Header="MenuItem 1"/>
</ContextMenu>
</Canvas.ContextMenu>
代码
private bool m_waitingForRightMouseDoubleClick = false;
private void scrollViewer_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Right)
{
if (m_waitingForRightMouseDoubleClick == false)
{
m_waitingForRightMouseDoubleClick = 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()
{
m_waitingForRightMouseDoubleClick = false;
}
));
}));
thread.Start();
}
else
{
MouseSimulator.ClickRightMouseButton();
}
}
}
<强> MouseSimulator.cs 强>
public class MouseSimulator
{
[DllImport("user32.dll", SetLastError = true)]
static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);
[StructLayout(LayoutKind.Sequential)]
struct INPUT
{
public SendInputEventType type;
public MouseKeybdhardwareInputUnion mkhi;
}
[StructLayout(LayoutKind.Explicit)]
struct MouseKeybdhardwareInputUnion
{
[FieldOffset(0)]
public MouseInputData mi;
[FieldOffset(0)]
public KEYBDINPUT ki;
[FieldOffset(0)]
public HARDWAREINPUT hi;
}
[StructLayout(LayoutKind.Sequential)]
struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
struct HARDWAREINPUT
{
public int uMsg;
public short wParamL;
public short wParamH;
}
struct MouseInputData
{
public int dx;
public int dy;
public uint mouseData;
public MouseEventFlags dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[Flags]
enum MouseEventFlags : uint
{
MOUSEEVENTF_MOVE = 0x0001,
MOUSEEVENTF_LEFTDOWN = 0x0002,
MOUSEEVENTF_LEFTUP = 0x0004,
MOUSEEVENTF_RIGHTDOWN = 0x0008,
MOUSEEVENTF_RIGHTUP = 0x0010,
MOUSEEVENTF_MIDDLEDOWN = 0x0020,
MOUSEEVENTF_MIDDLEUP = 0x0040,
MOUSEEVENTF_XDOWN = 0x0080,
MOUSEEVENTF_XUP = 0x0100,
MOUSEEVENTF_WHEEL = 0x0800,
MOUSEEVENTF_VIRTUALDESK = 0x4000,
MOUSEEVENTF_ABSOLUTE = 0x8000
}
enum SendInputEventType : int
{
InputMouse,
InputKeyboard,
InputHardware
}
public static void ClickRightMouseButton()
{
INPUT mouseDownInput = new INPUT();
mouseDownInput.type = SendInputEventType.InputMouse;
mouseDownInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_RIGHTDOWN;
SendInput(1, ref mouseDownInput, Marshal.SizeOf(new INPUT()));
INPUT mouseUpInput = new INPUT();
mouseUpInput.type = SendInputEventType.InputMouse;
mouseUpInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_RIGHTUP;
SendInput(1, ref mouseUpInput, Marshal.SizeOf(new INPUT()));
}
}