Сделать окно перетаскиваемым в пределах определенной границы WPF - PullRequest
3 голосов
/ 07 февраля 2011

У меня есть дочернее окно wpf, которое я могу перетаскивать с помощью метода DragMove ().Однако мне нужно разрешить перетаскивать окно только в пределах его родительского элемента управления.

Кто-нибудь может предложить способ достижения этого?Спасибо!

1 Ответ

5 голосов
/ 08 февраля 2011

Есть два способа сделать это.

Использование LocationEnded

Если вы обрабатываете это событие, вы можете изменить Top или Left набыть в пределах окна владельца.например,

    private void Window_LocationChanged(object sender, EventArgs e)
    {

        if (this.Left < this.Owner.Left)
            this.Left = this.Owner.Left;

        //... also right top and bottom
        //
    }

Это довольно легко написать, но он нарушает Принцип наименьшего удивления , поскольку он не ограничивает окно перетаскивания, он просто толкает окно на место, когдапользователь отпускает кнопку мыши.

Использование AddHook

Как отмечает Питер в ответ на аналогичный вопрос, который вы можете взаимодействовать с сообщениями Windowsи заблокировать окно перетаскивания.Это имеет приятный эффект , ограничивающий фактическое окно перетаскивания .

Вот пример кода, который я собрал для подхода AddHook

Начните с загруженного окна, чтобы добавить хук

  //In Window_Loaded the handle is there (earlier its null) so this is good time to add the handler 

   private void Window_Loaded(object sender, RoutedEventArgs e)
    {

        WindowInteropHelper helper = new WindowInteropHelper(this);
        HwndSource.FromHwnd(helper.Handle).AddHook(HwndSourceHookHandler);
    } 

В вашем обработчике вы хотите искать только перемещение или перемещение сообщения.Затем вы прочитаете прямоугольник lParam и увидите, выходит ли он за пределы.Если это так, вам нужно изменить значения прямоугольника lParam и вернуть его обратно.Заметьте, для краткости, я сделал только левую.Вам все равно нужно будет написать правый, верхний и нижний регистры.

 private IntPtr HwndSourceHookHandler(IntPtr hwnd, int msg, IntPtr wParam,
    IntPtr lParam, ref bool handled)
        {


const int WM_MOVING = 0x0216;
        const int WM_MOVE = 0x0003;


        switch (msg)
        {
            case WM_MOVING:
                {


                   //read the lparm ino a struct

                    MoveRectangle rectangle = (MoveRectangle)Marshal.PtrToStructure(
                      lParam, typeof(MoveRectangle));


                     //

                    if (rectangle.Left < this.Owner.Left)
                    {
                        rectangle.Left = (int)this.Owner.Left;
                        rectangle.Right = rectangle.Left + (int)this.Width;
                    }



                    Marshal.StructureToPtr(rectangle, lParam, true);

                    break;
                }
            case WM_MOVE:
                {
                   //Do the same thing as WM_MOVING You should probably enacapsulate that stuff so don'tn just copy and paste

                    break;
                }


        }

        return IntPtr.Zero;

    }

структура для lParam

  [StructLayout(LayoutKind.Sequential)]
    //Struct for Marshalling the lParam
    public struct MoveRectangle
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;

    }

Последнее замечание, которое вам необходимо выяснить, что делать, если вашему дочернему окну разрешено быть больше родительского окна.

...