Reputation: 124770
As you may have gathered from the title of this post, I am about to crack.
Ok, so here it is: I have a WPF window which is hosting a WinForms Form which is in turn hosting an ActiveX control. This is all due to legacy components and wanting to animate the opacity of a transparent WPF window. Can't you just feel the fun already?!
...So, I would like to be able to drag my transparent WPF window by calling DragMove in mouse down for various areas of the window. This works fine, and I can live with the current behavior, but it would be nice if I could also drag the window via a MouseDown event generated by my WinForms component. So, I took the obvious approach:
void Init()
{
MyWinForm form = new MyWinForm();
form.SomeControl.MouseDown = form_MouseDown;
}
void form_MouseDown( object sender, MouseEventArgs e )
{
if( e.Button == MouseButtons.Left )
{
DragMove();
}
}
However, my application crashes with the following message:
Can only call DragMove when primary mouse button is down.
Yeah, right, except the left (primary) button is the button being pressed (I realize this could be problematic for left handed mouses, but let's avoid that for now). So, once again, simple code that works for a Mouse event generated by a WPF control fails for a System.Windows.Forms.Control
. Anyone have any experience with this? Thanks in advance for any advice you can offer.
TLDR; Calling DragMove()
from inside a System.Windows.Controls.MouseDown
event crashes the app. I'm open to any workaround at this point.
Upvotes: 2
Views: 1093
Reputation: 1
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
if (e.LeftButton == MouseButtonState.Pressed)
Window.GetWindow(this).DragMove();
}
Upvotes: 0
Reputation: 34437
Looking at DragMove()
code using reflector, i've come to this solution: we can write or own DragMove(IntPtr hWnd)
, which does not perform button state check, but we must explicitly release mouse capture in MouseDown
event handler.
public static class Utility
{
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr h, int msg, IntPtr lp, IntPtr wp);
public static void DragMove(IntPtr hwnd)
{
const int WM_SYSCOMMAND = 0x112;
const int WM_LBUTTONUP = 0x202;
SendMessage(hwnd, WM_SYSCOMMAND, (IntPtr)0xf012, IntPtr.Zero);
SendMessage(hwnd, WM_LBUTTONUP, IntPtr.Zero, IntPtr.Zero);
}
}
and change your MouseDown handler just a bit:
void form_MouseDown( object sender, MouseEventArgs e )
{
if( e.Button == MouseButtons.Left )
{
// it is necessary to release mouse capture, so that
// WPF window will be able to capture mouse input
((Control)sender).Capture = false;
// use helper to acquire window handle
var helper = new System.Windows.Interop.WindowInteropHelper(
your_window_reference_goes_here);
Utility.DragMove(helper.Handle);
}
}
I didn't test it with ActiveX controls, but it works with simple WinForms control, hosted in WindowsFormsControlHost
at least on Win7 Ultimate x64.
Upvotes: 2