WPF窗口在限制上移动闪烁

时间:2015-06-18 13:43:39

标签: c# wpf

我有WPF无边界透明窗口。

使用this.DragMove();我可以成功地移动窗口。

我想限制屏幕区域内的窗口。 它也使用下面的代码段工作。

    private void Window_LocationChanged(object sender, EventArgs e)
            {
                CheckBounds();
    }

private void CheckBounds()
        {
            var height = System.Windows.SystemParameters.PrimaryScreenHeight;
            var width = System.Windows.SystemParameters.PrimaryScreenWidth;

            if (this.Left < 0)
                this.Left = 0;
            if (this.Top < 0)
                this.Top = 0;
            if (this.Top + this.Height > height)
                this.Top = height - this.Height;
            if (this.Left + this.Width > width)
                this.Left = width - this.Width;
        }

但是使用上面的代码,每当窗口使用鼠标拖动达到其最大界限时,它就会开始闪烁。

有人可以建议如何避免这种闪烁吗?

1 个答案:

答案 0 :(得分:1)

我知道处理此问题的最佳方法是在窗口中处理WM_MOVING窗口消息并调整其位置。由于在窗口实际移动之前收到WM_MOVING消息并允许修改位置,因此您永远不会看到任何抖动。以下是Window的示例代码隐藏。

using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
public partial class MainWindow : Window
{
    private HwndSource mSource;

    public MainWindow()
    {
        InitializeComponent();
    }

    protected override void OnSourceInitialized(EventArgs e)
    {
        base.OnSourceInitialized(e);

        mSource = (HwndSource)PresentationSource.FromVisual(this);
        mSource.AddHook(WndProc);
    }

    protected override void OnClosed(EventArgs e)
    {
        mSource.RemoveHook(WndProc);
        mSource.Dispose();
        mSource = null;

        base.OnClosed(e);
    }

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == (int)WindowsMessage.WM_MOVING)
        {
            // TODO: Substitute realistic bounds
            RECT bounds = new RECT() { Left = 0, Top = 0, Right = 1000, Bottom = 800 };

            RECT window = (RECT)Marshal.PtrToStructure(lParam, typeof(RECT));
            if (window.Left < bounds.Left)
            {
                window.Right = window.Right + bounds.Left - window.Left;
                window.Left = bounds.Left;
            }
            if (window.Top < bounds.Top)
            {
                window.Bottom = window.Bottom + bounds.Top - window.Top;
                window.Top = bounds.Top;
            }
            if (window.Right >= bounds.Right)
            {
                window.Left = bounds.Right - window.Right + window.Left - 1;
                window.Right = bounds.Right - 1;
            }
            if (window.Bottom >= bounds.Bottom)
            {
                window.Top = bounds.Bottom - window.Bottom + window.Top - 1;
                window.Bottom = bounds.Bottom - 1;
            }
            Marshal.StructureToPtr(window, lParam, true);

            handled = true;
            return new IntPtr(1);
        }

        handled = false;
        return IntPtr.Zero;
    }
}

以下是代码中使用的辅助对象:

[StructLayout(LayoutKind.Sequential)]
struct RECT
{
    public int Left, Top, Right, Bottom;
}

enum WindowsMessage
{
    WM_MOVING = 0x0216
}

P.S。调用LocationChanged事件(以及关联的OnLocationChanged覆盖)以响应WM_MOVE,在窗口已经移动之前不会调用它。似乎没有相应的OnLocationChanging事件。