Как вы, возможно, догадались из названия этого поста, я собираюсь взломать.

Итак, вот оно: у меня есть окно WPF, в котором размещается форма WinForms, которая, в свою очередь, размещает элемент управления ActiveX. Все это связано с устаревшими компонентами и желанием анимировать непрозрачность прозрачного окна WPF. Разве ты уже не чувствуешь веселье ?!

... Итак, я хотел бы иметь возможность перетаскивать свое прозрачное окно WPF, вызывая DragMove с помощью мыши вниз для различных областей окна. Это работает нормально, и я могу жить с текущим поведением, но было бы неплохо, если бы я также мог перетащить окно через событие MouseDown, сгенерированное моим компонентом WinForms. Итак, я выбрал очевидный подход:

void Init()
{
    MyWinForm form = new MyWinForm();
    form.SomeControl.MouseDown = form_MouseDown;
}

void form_MouseDown( object sender, MouseEventArgs e )
{
    if( e.Button == MouseButtons.Left )
    {
        DragMove();
    }
}

Однако мое приложение вылетает со следующим сообщением:

Может вызывать DragMove, только когда основная кнопка мыши нажата.

Да, правая, за исключением того, что левая (основная) кнопка является нажатой кнопкой (я понимаю, что это может быть проблематично для леворуких мышей, но давайте пока этого избегаем). Итак, еще раз, простой код, который работает для события Mouse, созданного элементом управления WPF, не работает для System.Windows.Forms.Control. У кого-нибудь есть опыт в этом? Заранее благодарим за любой совет, который вы можете предложить.

TL; DR; Вызов DragMove() из события System.Windows.Controls.MouseDown приводит к сбою приложения. На данный момент я открыт для любого обходного пути.

2
Ed S. 18 Мар 2011 в 06:52

2 ответа

Лучший ответ

Посмотрев на код DragMove() с использованием отражателя, я пришел к следующему решению: мы можем написать или владеть DragMove(IntPtr hWnd), который не выполняет проверку состояния кнопки, но мы должны явно освободить захват мыши в MouseDown обработчик события.

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);
    }
}

И немного измените обработчик MouseDown:

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);
    }
}

Я не тестировал его с элементами управления ActiveX, но он работает с простым элементом управления WinForms, размещенным в WindowsFormsControlHost, по крайней мере, на Win7 Ultimate x64.

2
max 18 Мар 2011 в 08:23
Почему я всегда забываю про Reflector? ... В любом случае, вы, сэр, очень помогли. Большое спасибо, он отлично работает и научил меня чему-то новому. Ваше здоровье.
 – 
Ed S.
18 Мар 2011 в 19:55
    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
        base.OnMouseLeftButtonDown(e);
        if (e.LeftButton == MouseButtonState.Pressed)
            Window.GetWindow(this).DragMove();
    }
0
Victor B. 10 Янв 2019 в 12:17
3
Вы можете добавить пояснение?
 – 
executable
10 Янв 2019 в 12:21