使WPF弹出窗口不绑定屏幕

7

弹出窗口的默认行为是,如果它被放置在超出屏幕边缘的位置,弹出窗口将重新定位。有没有一种方法可以关闭这种行为?

我有一个弹出窗口,用户可以在屏幕上拖动它。然而,当它到达边缘时就会卡住。它会卡在边缘处,并保持在那里,直到鼠标被远离边缘拖动。此外,我有两个显示器,当弹出窗口被拖到两个显示器共享的边缘时,我会看到闪烁。弹出窗口在两个显示器之间闪烁。

2个回答

3

只需使用interop来移动弹出窗口(拖动它们)

这里是Thumb的代码,它将跟踪拖动过程

区域Thumb

    private Thumb mThumb = null;
    public Thumb Thumb
    {
        get { return mThumb; }
        set
        {
            if (mThumb != value)
            {
                if (mThumb != null)
                {
                    DetachThumb();
                }
                mThumb = value;
                if (mThumb != null)
                {
                    AttachThumb();
                }
            }
        }
    }

    private void AttachThumb()
    {
        Thumb.DragStarted += Thumb_DragStarted;
        Thumb.DragDelta += Thumb_DragDelta;
        Thumb.DragCompleted += Thumb_DragCompleted;
    }

    private void DetachThumb()
    {
        Thumb.DragStarted -= Thumb_DragStarted;
        Thumb.DragDelta -= Thumb_DragDelta;
        Thumb.DragCompleted -= Thumb_DragCompleted;
    }

    private void Thumb_DragStarted(object sender, DragStartedEventArgs e)
    {
        mIsThumbDragging = true;
        mPreviousDiffX = 0;
        mPreviousDiffY = 0;
    }

    private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
    {
        if (mIsMoving)
        {
            return;
        }
        mIsMoving = true;
        try
        {
            if (mIsThumbDragging)
            {
                var doubleDetaX = e.HorizontalChange + mPreviousDiffX;
                var doubleDetaY = e.VerticalChange + mPreviousDiffY;

                var deltaX = (int)doubleDetaX;
                var deltaY = (int)doubleDetaY;

                mPreviousDiffX = (double)deltaX - doubleDetaX;
                mPreviousDiffY = (double)deltaY - doubleDetaY;

                HostPopup.Move(deltaX, deltaY);
            }
        }
        finally
        {
            mIsMoving = false;
        }
    }

    private void Thumb_DragCompleted(object sender, DragCompletedEventArgs e)
    {
        mIsThumbDragging = false;
    }

    #endregion

HostPopup类是Popup的子类,它使用Interop具有以下方法来移动窗口:

    [DllImport("user32.dll", SetLastError = true)]
    internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);

     [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
    
    internal void Move(int deltaX, int deltaY)
    {
        if (mIsMoving)
        {
            return;
        }
        mIsMoving = true;
        try
        {
            if (Child == null)
                return;

            var hwndSource = (PresentationSource.FromVisual(Child)) as HwndSource;

            if (hwndSource == null)
                return;
            var hwnd = hwndSource.Handle;

            RECT rect;

            if (!GetWindowRect(hwnd, out rect))
                return;

            MoveWindow(hwnd, rect.Left + deltaX, rect.Top + deltaY, (int)Width, (int)Height, true);
        }
        finally
        {
            mIsMoving = false;
        }
    }

1
有人能否进一步解释如何实现这个?我如何获取HostPopup子类的访问权限?GetWindowRect()方法位于哪里? - Saggio

2
如果您希望弹出窗口的行为更像一个窗口,那么我建议您创建一个窗口而不是弹出窗口。让一个弹出窗口不像标准的弹出窗口那样定位,并允许您在屏幕上拖动它,这似乎只会导致低可用性和混乱。

3
很遗憾,弹出窗口具有窗口不具备的功能,并且对我来说比运动自由更重要。我想我必须限制移动范围,以确保不会超出屏幕边界,从而避免重新定位和闪烁。谢谢信息。 - Dan Vogel
1
同意。我希望弹出窗口跟随窗口移动,并防止在WPF应用程序中托管的WinForm控件(基本上是繁忙指示器)中输入,如果窗口被拖到屏幕外,则弹出窗口不会超出屏幕边界跟随窗口。 - Stephen Price
另一个数据点是,有时弹出窗口比窗口更适合拖动内容,因为在 Windows 10 上使用平板模式打开窗口会触发 Win10 的屏幕分割操作并干扰拖动。(背景:我正在临时使用弹出窗口作为拖动反馈窗口,而不是 UI 的永久部分) - jschroedl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接