DragMove()和Maximize

时间:2012-07-28 19:05:16

标签: wpf drag move maximize

我的自定义窗口(AllowTransparency,WindowStyle = None)在WPF中有问题。 DragMove()方法效果很好,但是当我最大化窗口,或者它通过Windows 7 Aero Snap自动最大化时,此方法根本不起作用。所以我无法用鼠标拖动来取消窗口并将其状态返回到WindowState.Normal。左右Aero Snap工作正常,我可以快速捕捉和取消窗口。但是当它最大化时,除了Win + Down组合之外没有任何作用。也许有人知道如何解决这个问题,或者我在哪里可以通过工作的Aero Snap功能找到其他方法来自定义窗口的DragMove?

6 个答案:

答案 0 :(得分:14)

这是我的方法。尝试缩短)))

private void InitHeader()
{
    var border = Find<Border>("borderHeader");
    var restoreIfMove = false;

    border.MouseLeftButtonDown += (s, e) =>
    {
        if (e.ClickCount == 2)
        {
            if ((ResizeMode == ResizeMode.CanResize) ||
                (ResizeMode == ResizeMode.CanResizeWithGrip))
            {
                SwitchState();
            }
        }
        else
        {
            if (WindowState == WindowState.Maximized)
            {
                restoreIfMove = true;
            }

            DragMove();
        }
    };
    border.MouseLeftButtonUp += (s, e) =>
    {
        restoreIfMove = false;
    };
    border.MouseMove += (s, e) =>
    {
        if (restoreIfMove)
        {
            restoreIfMove = false;
            var mouseX = e.GetPosition(this).X;
            var width = RestoreBounds.Width;
            var x = mouseX - width / 2;

            if (x < 0)
            {
                x = 0;
            }
            else
            if (x + width > screenSize.X)
            {
                x = screenSize.X - width;
            }

            WindowState = WindowState.Normal;
            Left = x;
            Top = 0;
            DragMove();
        }
    };
}

private void SwitchState()
{
    switch (WindowState)
    {
        case WindowState.Normal:
        {
            WindowState = WindowState.Maximized;
            break;
        }
        case WindowState.Maximized:
        {
            WindowState = WindowState.Normal;
            break;
        }
    }
}

(要获取screenSize,我使用本机方法)

答案 1 :(得分:12)

Groaner的解决方案无法在多个显示器设置下正常运行,尤其是在主显示器不在最左侧的情况下。

这是我的解决方案,基于他正确处理单个或多个显示器设置。 在此代码中,'rctHeader'是在XAML中定义的Rectangle。

    private bool mRestoreIfMove = false;


    public MainWindow()
    {
        InitializeComponent();
    }


    private void SwitchWindowState()
    {
        switch (WindowState)
        {
            case WindowState.Normal:
                {
                    WindowState = WindowState.Maximized;
                    break;
                }
            case WindowState.Maximized:
                {
                    WindowState = WindowState.Normal;
                    break;
                }
        }
    }


    private void rctHeader_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if (e.ClickCount == 2)
        {
            if ((ResizeMode == ResizeMode.CanResize) || (ResizeMode == ResizeMode.CanResizeWithGrip))
            {
                SwitchWindowState();
            }

            return;
        }

        else if (WindowState == WindowState.Maximized)
        {
            mRestoreIfMove = true;
            return;
        }

        DragMove();
    }


    private void rctHeader_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        mRestoreIfMove = false;
    }


    private void rctHeader_MouseMove(object sender, MouseEventArgs e)
    {
        if (mRestoreIfMove)
        {
            mRestoreIfMove = false;

            double percentHorizontal = e.GetPosition(this).X / ActualWidth;
            double targetHorizontal = RestoreBounds.Width * percentHorizontal;

            double percentVertical = e.GetPosition(this).Y / ActualHeight;
            double targetVertical = RestoreBounds.Height * percentVertical;

            WindowState = WindowState.Normal;

            POINT lMousePosition;
            GetCursorPos(out lMousePosition);

            Left = lMousePosition.X - targetHorizontal;
            Top = lMousePosition.Y - targetVertical;

            DragMove();
        }
    }



    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool GetCursorPos(out POINT lpPoint);


    [StructLayout(LayoutKind.Sequential)]
    public struct POINT
    {
        public int X;
        public int Y;

        public POINT(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }
    }


}

答案 2 :(得分:7)

在WPF中,我强烈建议您在Control.PointToScreen之前恢复窗口时使用Window.DragMove。 PointToScreen还将处理多个显示器设置。这将简化恢复到以下内容:

    private void OnMouseLeftButtonDown( object sender, MouseButtonEventArgs e )
    {
        if( e.ClickCount == 2 )
        {
            if( ResizeMode != ResizeMode.CanResize && 
                ResizeMode != ResizeMode.CanResizeWithGrip )
            {
                return;
            }

            WindowState = WindowState == WindowState.Maximized
                ? WindowState.Normal
                : WindowState.Maximized;
        }
        else
        {
            mRestoreForDragMove = WindowState == WindowState.Maximized;
            DragMove();
        }
    }

    private void OnMouseMove( object sender, MouseEventArgs e )
    {
        if( mRestoreForDragMove )
        {
            mRestoreForDragMove = false;

            var point = PointToScreen( e.MouseDevice.GetPosition( this ) );

            Left = point.X - ( RestoreBounds.Width * 0.5 );
            Top = point.Y;

            WindowState = WindowState.Normal;

            DragMove();
        }
    }

    private void OnMouseLeftButtonUp( object sender, MouseButtonEventArgs e )
    {
        mRestoreForDragMove = false;
    }

    private bool mRestoreForDragMove;

答案 3 :(得分:3)

另一个答案有点晚了,但我的代码更简单,所以我把它放在这里。 正如你所做的那样,左右对齐的工作正常,但是当窗口最大化或捕捉到上部屏幕边界并最大化时,DragMove方法将无法工作!

只需处理要拖动的元素上的Mouse_Down事件,如下所示:

private void TitleBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    if (WindowState == WindowState.Maximized)
    {
        var point = PointToScreen(e.MouseDevice.GetPosition(this));

        if (point.X <= RestoreBounds.Width / 2)
            Left = 0;

        else if (point.X >= RestoreBounds.Width)
            Left = point.X - (RestoreBounds.Width - (this.ActualWidth - point.X));

        else
            Left = point.X - (RestoreBounds.Width / 2);

        Top = point.Y - (((FrameworkElement)sender).ActualHeight / 2);
        WindowState = WindowState.Normal;
    }
    DragMove(); 
}

我希望它有所帮助!

答案 4 :(得分:0)

答案 5 :(得分:0)

DragMove()方法仅在表单的标题栏中起作用,因此请使用:

"Limit  (cost=25.62..1349.23 rows=206 width=202) (actual time=0.359..0.359 rows=0 loops=1)"
"  ->  Nested Loop  (cost=25.62..1349.23 rows=206 width=202) (actual time=0.357..0.357 rows=0 loops=1)"
"        Join Filter: (notifications.device_id = devices.id)"
"        ->  Nested Loop  (cost=25.33..1258.73 rows=206 width=206) (actual time=0.357..0.357 rows=0 loops=1)"
"              ->  Hash Join  (cost=25.04..61.32 rows=206 width=52) (actual time=0.043..0.172 rows=193 loops=1)"
"                    Hash Cond: (notifications.event_id = events.id)"
"                    ->  Index Scan using idx_notifications_status on notifications  (cost=0.42..33.87 rows=206 width=16) (actual time=0.013..0.100 rows=193 loops=1)"
"                          Index Cond: (status = 'pending'::notification_status)"
"                          Filter: (region = 'ap-southeast-2'::text)"
"                    ->  Hash  (cost=16.50..16.50 rows=650 width=40) (actual time=0.022..0.022 rows=34 loops=1)"
"                          Buckets: 1024  Batches: 1  Memory Usage: 14kB"
"                          ->  Seq Scan on events  (cost=0.00..16.50 rows=650 width=40) (actual time=0.005..0.014 rows=34 loops=1)"
"              ->  Index Scan using idx_device_endpoints_device_id on device_endpoints  (cost=0.29..5.80 rows=1 width=154) (actual time=0.001..0.001 rows=0 loops=193)"
"                    Index Cond: (device_id = notifications.device_id)"
"        ->  Index Scan using devices_pkey on devices  (cost=0.29..0.43 rows=1 width=4) (never executed)"
"              Index Cond: (id = device_endpoints.device_id)"
"              Filter: (device_id ~ '[0-9a-f].*'::text)"
"Planning time: 0.693 ms"
"Execution time: 0.404 ms"

不要忘记添加System.Windows.Interop