Mise à jour
Projet de petit échantillon téléchargé démontrant l'effet.
http://www.mediafire.com/?du2jr18khx8ooy9
J'ai essayé un tas de différentes approches pour cela, et la chose la plus proche que j'ai trouvé pour compenser la HorizontalOffset par 1 pour le ContextMenu. Cela permettait un double-clic droit lorsque le ContextMenu était ouvert. Cela ne fonctionnait toujours pas lorsque le ContextMenu n'était pas ouvert car le ScrollViewer ne recevait que le premier clic. Vous pouvez contourner ce problème en utilisant votre code temporel pour le premier clic droit de la souris et si un autre clic droit de la souris se produit avant l'expiration du thread, vous simulez un autre clic droit en utilisant SendInput. Bien que ce ne soit pas si joli, je fais le travail.
<Canvas ...>
<Canvas.ContextMenu>
<ContextMenu Placement="RelativePoint" HorizontalOffset="1">
<MenuItem Header="MenuItem 1"/>
</ContextMenu>
</Canvas.ContextMenu>
code derrière
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()));
}
}
Pourquoi ne pas ignorer le menu contextuel et utiliser une fenêtre contextuelle pour construire la fonctionnalité exacte que vous désirez ? –
@Aaron: cela ne change rien. Le problème reste le même, menu contextuel ou popup ... – serhio