Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/270.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# SetWindowPlacement赢得';无法正确放置WPF工具窗口_C#_Wpf_Winapi - Fatal编程技术网

C# SetWindowPlacement赢得';无法正确放置WPF工具窗口

C# SetWindowPlacement赢得';无法正确放置WPF工具窗口,c#,wpf,winapi,C#,Wpf,Winapi,我正在我的WPF应用程序中对进行p调用,以保存和恢复窗口位置。这非常有效,但是当窗口是工具窗口而不是标准窗口时,确保窗口永远不会完全隐藏的广告功能似乎不起作用。您调用SetWindowPlacement,左、右位置为负数,它会很高兴地在屏幕外打开它,而无法重新打开它 有没有办法让SetWindowPlacement更正这些工具窗口的位置(对于缺少的监视器等) 如果做不到这一点,有没有一种好的手动方法?以下守则供参考: // RECT structure required by WINDOWPLA

我正在我的WPF应用程序中对进行p调用,以保存和恢复窗口位置。这非常有效,但是当窗口是工具窗口而不是标准窗口时,确保窗口永远不会完全隐藏的广告功能似乎不起作用。您调用SetWindowPlacement,左、右位置为负数,它会很高兴地在屏幕外打开它,而无法重新打开它

有没有办法让SetWindowPlacement更正这些工具窗口的位置(对于缺少的监视器等)

如果做不到这一点,有没有一种好的手动方法?以下守则供参考:

// RECT structure required by WINDOWPLACEMENT structure
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;

    public RECT(int left, int top, int right, int bottom)
    {
        this.Left = left;
        this.Top = top;
        this.Right = right;
        this.Bottom = bottom;
    }
}

// POINT structure required by WINDOWPLACEMENT structure
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
    public int X;
    public int Y;

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

// WINDOWPLACEMENT stores the position, size, and state of a window
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct WINDOWPLACEMENT
{
    public int length;
    public int flags;
    public int showCmd;
    public POINT minPosition;
    public POINT maxPosition;
    public RECT normalPosition;
}

public static class WindowPlacement
{
    private static Encoding encoding = new UTF8Encoding();
    private static XmlSerializer serializer = new XmlSerializer(typeof(WINDOWPLACEMENT));

    [DllImport("user32.dll")]
    private static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl);

    [DllImport("user32.dll")]
    private static extern bool GetWindowPlacement(IntPtr hWnd, out WINDOWPLACEMENT lpwndpl);

    private const int SW_SHOWNORMAL = 1;
    private const int SW_SHOWMINIMIZED = 2;

    public static void SetPlacement(IntPtr windowHandle, string placementXml)
    {
        if (string.IsNullOrEmpty(placementXml))
        {
            return;
        }

        WINDOWPLACEMENT placement;
        byte[] xmlBytes = encoding.GetBytes(placementXml);

        try
        {
            using (MemoryStream memoryStream = new MemoryStream(xmlBytes))
            {
                placement = (WINDOWPLACEMENT)serializer.Deserialize(memoryStream);
            }

            placement.length = Marshal.SizeOf(typeof(WINDOWPLACEMENT));
            placement.flags = 0;
            placement.showCmd = (placement.showCmd == SW_SHOWMINIMIZED ? SW_SHOWNORMAL : placement.showCmd);

            SetWindowPlacement(windowHandle, ref placement);
        }
        catch (InvalidOperationException)
        {
            // Parsing placement XML failed. Fail silently.
        }
    }

    public static string GetPlacement(IntPtr windowHandle)
    {
        WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
        GetWindowPlacement(windowHandle, out placement);

        using (MemoryStream memoryStream = new MemoryStream())
        {
            using (XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8))
            {
                serializer.Serialize(xmlTextWriter, placement);
                byte[] xmlBytes = memoryStream.ToArray();
                return encoding.GetString(xmlBytes);
            }
        }
    }
}

使用顶部:200,底部:600,左侧:-1000,右侧:-300调用SetPlacement。

您可以使用
MONITOR\u DEFAULTTONEAREST
标志将建议的窗口矩形传递给
MonitorFromRect()
。这将返回一个
HMONITOR
,表示窗口最相交的监视器(打开)-或者如果窗口完全脱离屏幕,则返回距离建议坐标最近的监视器


然后,您可以调用
GetMonitorInfo()
查找监视器的显示和工作区矩形,并检查您建议的窗口坐标,以确保在显示窗口之前窗口完全在屏幕上。

根据Jonathan的回答,我想出了以下代码手动拯救窗口:

[StructLayout(LayoutKind.Sequential)]
public struct MONITORINFO
{
    public int cbSize;
    public RECT rcMonitor;
    public RECT rcWork;
    public uint dwFlags;
}

private static bool RectanglesIntersect(RECT a,RECT b)
{
如果(a.左>b.右| a.右b.Bottom | a.Bottom监视器宽度)
{
宽度=监视器宽度;
}
windowRect.Left=监视器rect.Left;
windowRect.Right=windowRect.Left+宽度;
}
else if(windowRect.Left>monitorect.Right)
{
//偏右
int width=windowRect.Right-windowRect.Left;
如果(宽度>监视器宽度)
{
宽度=监视器宽度;
}
windowRect.Right=monitorect.Right;
windowRect.Left=windowRect.Right-宽度;
}
if(windowRect.Bottom监视器高度)
{
高度=监视器高度;
}
windowRect.Top=monitorect.Top;
windowRect.Bottom=windowRect.Top+高度;
}
else if(windowRect.Top>monitorect.Bottom)
{
//下流的
int height=windowRect.Bottom-windowRect.Top;
如果(高度>监视器高度)
{
高度=监视器高度;
}
windowRect.Bottom=monitorect.Bottom;
windowRect.Top=windowRect.Bottom-高度;
}
返回windowRect;
}

我想出了一个解决方案(基于RandomEngy的代码),该解决方案使用KeepInsideNearestMonitor()方法扩展了Window类,确保WPF窗口放置在当前可见的边界内。它不带Win32,并且与调用因子有关,您可以通过右键单击桌面>显示设置在Windows 10中设置调用因子

public static class WindowExtension
{
    [StructLayout(LayoutKind.Sequential)]
    internal struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;

        public RECT(int left, int top, int right, int bottom)
        {
            this.Left = left;
            this.Top = top;
            this.Right = right;
            this.Bottom = bottom;
        }
    }

    internal static void KeepInsideNearestMonitor(this Window floatingWindow)
    {
        RECT normalPosition = new RECT();
        normalPosition.Left = (int)floatingWindow.FloatingLeft;
        normalPosition.Top = (int)floatingWindow.FloatingTop;
        normalPosition.Bottom = normalPosition.Top + (int)floatingWindow.FloatingHeight;
        normalPosition.Right = normalPosition.Left + (int)floatingWindow.FloatingWidth;

        // Are we using only one monitor?
        if (SystemParameters.PrimaryScreenWidth == SystemParameters.VirtualScreenWidth &&
            SystemParameters.PrimaryScreenHeight == SystemParameters.VirtualScreenHeight)
        {
            RECT primaryscreen = new RECT(0,0, (int)SystemParameters.PrimaryScreenWidth, (int)SystemParameters.PrimaryScreenHeight);

            if (!RectanglesIntersect(normalPosition, primaryscreen))
            {
                normalPosition = PlaceOnScreen(primaryscreen, normalPosition);

                floatingWindow.FloatingLeft = normalPosition.Left;
                floatingWindow.FloatingTop = normalPosition.Top;
                floatingWindow.FloatingHeight = normalPosition.Bottom - normalPosition.Top;
                floatingWindow.FloatingWidth = normalPosition.Right - normalPosition.Left;
            }

            return;
        }
        else
        {
            RECT primaryscreen = new RECT(0, 0, (int)SystemParameters.VirtualScreenWidth, (int)SystemParameters.VirtualScreenHeight);

            if (!RectanglesIntersect(normalPosition, primaryscreen))
            {
                normalPosition = PlaceOnScreen(primaryscreen, normalPosition);

                floatingWindow.FloatingLeft = normalPosition.Left;
                floatingWindow.FloatingTop = normalPosition.Top;
                floatingWindow.FloatingHeight = normalPosition.Bottom - normalPosition.Top;
                floatingWindow.FloatingWidth = normalPosition.Right - normalPosition.Left;
            }

            return;
        }
    }

    /// <summary>
    /// Determine whether <paramref name="a"/> and <paramref name="b"/>
    /// have an intersection or not.
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    /// <returns></returns>
    private static bool RectanglesIntersect(RECT a, RECT b)
    {
        if (a.Left > b.Right || a.Right < b.Left)
        {
            return false;
        }

        if (a.Top > b.Bottom || a.Bottom < b.Top)
        {
            return false;
        }

        return true;
    }

    /// <summary>
    /// Determine the place where <paramref name="windowRect"/> should be placed
    /// inside the <paramref name="monitorRect"/>.
    /// </summary>
    /// <param name="monitorRect"></param>
    /// <param name="windowRect"></param>
    /// <returns></returns>
    private static RECT PlaceOnScreen(RECT monitorRect, RECT windowRect)
    {
        int monitorWidth = monitorRect.Right - monitorRect.Left;
        int monitorHeight = monitorRect.Bottom - monitorRect.Top;

        if (windowRect.Right < monitorRect.Left)
        {
            // Off left side
            int width = windowRect.Right - windowRect.Left;
            if (width > monitorWidth)
            {
                width = monitorWidth;
            }

            windowRect.Left = monitorRect.Left;
            windowRect.Right = windowRect.Left + width;
        }
        else if (windowRect.Left > monitorRect.Right)
        {
            // Off right side
            int width = windowRect.Right - windowRect.Left;
            if (width > monitorWidth)
            {
                width = monitorWidth;
            }

            windowRect.Right = monitorRect.Right;
            windowRect.Left = windowRect.Right - width;
        }

        if (windowRect.Bottom < monitorRect.Top)
        {
            // Off top
            int height = windowRect.Bottom - windowRect.Top;
            if (height > monitorHeight)
            {
                height = monitorHeight;
            }

            windowRect.Top = monitorRect.Top;
            windowRect.Bottom = windowRect.Top + height;
        }
        else if (windowRect.Top > monitorRect.Bottom)
        {
            // Off bottom
            int height = windowRect.Bottom - windowRect.Top;
            if (height > monitorHeight)
            {
                height = monitorHeight;
            }

            windowRect.Bottom = monitorRect.Bottom;
            windowRect.Top = windowRect.Bottom - height;
        }

        return windowRect;
    }
}
公共静态类窗口扩展
{
[StructLayout(LayoutKind.Sequential)]
内部结构矩形
{
公共int左;
公共int Top;
公共权利;
公共int底部;
公共矩形(左整数、上整数、右整数、下整数)
{
这个。左=左;
这个.Top=Top;
这个。右=右;
这个。底部=底部;
}
}
内部静态void keepinsidenearest监视器(此窗口浮动窗口)
{
RECT normalPosition=new RECT();
normalPosition.Left=(int)floatingWindow.FloatingLeft;
normalPosition.Top=(int)floatingWindow.FloatingTop;
normalPosition.Bottom=normalPosition.Top+(int)floatingWindow.FloatingHeight;
normalPosition.Right=normalPosition.Left+(int)floatingWindow.FloatingWidth;
//我们只使用一个监视器吗?
if(SystemParameters.PrimaryScreenWidth==SystemParameters.VirtualScreenWidth&&
SystemParameters.PrimaryScreenHeight==SystemParameters.VirtualScreenHeight)
{
RECT primaryscreen=new RECT(0,0,(int)SystemParameters.PrimaryScreenWidth,(int)SystemParameters.PrimaryScreenHeight);
如果(!矩形切分(正常位置,主屏幕))
{
法线位置=屏幕上的位置(主屏幕,法线位置);
floatingWindow.FloatingLeft=法线位置.Left;
floatingWindow.FloatingTop=法线位置.Top;
floatingWindow.FloatingHeight=normalPosition.Bottom-normalPosition.Top;
floatingWindow.FloatingWidth=normalPosition.Right-normalPosition.Left;
}
返回;
}
其他的
{
RECT primaryscreen=new RECT(0,0,(int)SystemParameters.VirtualScreenWidth,(int)SystemParameters.VirtualScreenHeight);
如果(!矩形切分(正常位置,主屏幕))
{
法线位置=屏幕上的位置(主屏幕,法线位置);
floatingWindow.FloatingLeft=法线位置.Left;
floatingWindow.FloatingTop=法线位置.Top;
floatingWindow.FloatingHeight=normalPosition.Bottom-normalPosition.Top;
floatingWindow.FloatingWidth=normalPosition.Right-normalPosition.Left;
}
返回;
}
IntPtr closestMonitorPtr = MonitorFromRect(ref placement.normalPosition, MONITOR_DEFAULTTONEAREST);
MONITORINFO closestMonitorInfo = new MONITORINFO();
closestMonitorInfo.cbSize = Marshal.SizeOf(typeof (MONITORINFO));
bool getInfoSucceeded = GetMonitorInfo(closestMonitorPtr, ref closestMonitorInfo);

if (getInfoSucceeded && !RectanglesIntersect(placement.normalPosition, closestMonitorInfo.rcMonitor))
{
    placement.normalPosition = PlaceOnScreen(closestMonitorInfo.rcMonitor, placement.normalPosition);
}
private static bool RectanglesIntersect(RECT a, RECT b)
{
    if (a.Left > b.Right || a.Right < b.Left)
    {
        return false;
    }

    if (a.Top > b.Bottom || a.Bottom < b.Top)
    {
        return false;
    }

    return true;
}

private static RECT PlaceOnScreen(RECT monitorRect, RECT windowRect)
{
    int monitorWidth = monitorRect.Right - monitorRect.Left;
    int monitorHeight = monitorRect.Bottom - monitorRect.Top;

    if (windowRect.Right < monitorRect.Left)
    {
        // Off left side
        int width = windowRect.Right - windowRect.Left;
        if (width > monitorWidth)
        {
            width = monitorWidth;
        }

        windowRect.Left = monitorRect.Left;
        windowRect.Right = windowRect.Left + width;
    }
    else if (windowRect.Left > monitorRect.Right)
    {
        // Off right side
        int width = windowRect.Right - windowRect.Left;
        if (width > monitorWidth)
        {
            width = monitorWidth;
        }

        windowRect.Right = monitorRect.Right;
        windowRect.Left = windowRect.Right - width;
    }

    if (windowRect.Bottom < monitorRect.Top)
    {
        // Off top
        int height = windowRect.Bottom - windowRect.Top;
        if (height > monitorHeight)
        {
            height = monitorHeight;
        }

        windowRect.Top = monitorRect.Top;
        windowRect.Bottom = windowRect.Top + height;
    }
    else if (windowRect.Top > monitorRect.Bottom)
    {
        // Off bottom
        int height = windowRect.Bottom - windowRect.Top;
        if (height > monitorHeight)
        {
            height = monitorHeight;
        }

        windowRect.Bottom = monitorRect.Bottom;
        windowRect.Top = windowRect.Bottom - height;
    }

    return windowRect;
}
public static class WindowExtension
{
    [StructLayout(LayoutKind.Sequential)]
    internal struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;

        public RECT(int left, int top, int right, int bottom)
        {
            this.Left = left;
            this.Top = top;
            this.Right = right;
            this.Bottom = bottom;
        }
    }

    internal static void KeepInsideNearestMonitor(this Window floatingWindow)
    {
        RECT normalPosition = new RECT();
        normalPosition.Left = (int)floatingWindow.FloatingLeft;
        normalPosition.Top = (int)floatingWindow.FloatingTop;
        normalPosition.Bottom = normalPosition.Top + (int)floatingWindow.FloatingHeight;
        normalPosition.Right = normalPosition.Left + (int)floatingWindow.FloatingWidth;

        // Are we using only one monitor?
        if (SystemParameters.PrimaryScreenWidth == SystemParameters.VirtualScreenWidth &&
            SystemParameters.PrimaryScreenHeight == SystemParameters.VirtualScreenHeight)
        {
            RECT primaryscreen = new RECT(0,0, (int)SystemParameters.PrimaryScreenWidth, (int)SystemParameters.PrimaryScreenHeight);

            if (!RectanglesIntersect(normalPosition, primaryscreen))
            {
                normalPosition = PlaceOnScreen(primaryscreen, normalPosition);

                floatingWindow.FloatingLeft = normalPosition.Left;
                floatingWindow.FloatingTop = normalPosition.Top;
                floatingWindow.FloatingHeight = normalPosition.Bottom - normalPosition.Top;
                floatingWindow.FloatingWidth = normalPosition.Right - normalPosition.Left;
            }

            return;
        }
        else
        {
            RECT primaryscreen = new RECT(0, 0, (int)SystemParameters.VirtualScreenWidth, (int)SystemParameters.VirtualScreenHeight);

            if (!RectanglesIntersect(normalPosition, primaryscreen))
            {
                normalPosition = PlaceOnScreen(primaryscreen, normalPosition);

                floatingWindow.FloatingLeft = normalPosition.Left;
                floatingWindow.FloatingTop = normalPosition.Top;
                floatingWindow.FloatingHeight = normalPosition.Bottom - normalPosition.Top;
                floatingWindow.FloatingWidth = normalPosition.Right - normalPosition.Left;
            }

            return;
        }
    }

    /// <summary>
    /// Determine whether <paramref name="a"/> and <paramref name="b"/>
    /// have an intersection or not.
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    /// <returns></returns>
    private static bool RectanglesIntersect(RECT a, RECT b)
    {
        if (a.Left > b.Right || a.Right < b.Left)
        {
            return false;
        }

        if (a.Top > b.Bottom || a.Bottom < b.Top)
        {
            return false;
        }

        return true;
    }

    /// <summary>
    /// Determine the place where <paramref name="windowRect"/> should be placed
    /// inside the <paramref name="monitorRect"/>.
    /// </summary>
    /// <param name="monitorRect"></param>
    /// <param name="windowRect"></param>
    /// <returns></returns>
    private static RECT PlaceOnScreen(RECT monitorRect, RECT windowRect)
    {
        int monitorWidth = monitorRect.Right - monitorRect.Left;
        int monitorHeight = monitorRect.Bottom - monitorRect.Top;

        if (windowRect.Right < monitorRect.Left)
        {
            // Off left side
            int width = windowRect.Right - windowRect.Left;
            if (width > monitorWidth)
            {
                width = monitorWidth;
            }

            windowRect.Left = monitorRect.Left;
            windowRect.Right = windowRect.Left + width;
        }
        else if (windowRect.Left > monitorRect.Right)
        {
            // Off right side
            int width = windowRect.Right - windowRect.Left;
            if (width > monitorWidth)
            {
                width = monitorWidth;
            }

            windowRect.Right = monitorRect.Right;
            windowRect.Left = windowRect.Right - width;
        }

        if (windowRect.Bottom < monitorRect.Top)
        {
            // Off top
            int height = windowRect.Bottom - windowRect.Top;
            if (height > monitorHeight)
            {
                height = monitorHeight;
            }

            windowRect.Top = monitorRect.Top;
            windowRect.Bottom = windowRect.Top + height;
        }
        else if (windowRect.Top > monitorRect.Bottom)
        {
            // Off bottom
            int height = windowRect.Bottom - windowRect.Top;
            if (height > monitorHeight)
            {
                height = monitorHeight;
            }

            windowRect.Bottom = monitorRect.Bottom;
            windowRect.Top = windowRect.Bottom - height;
        }

        return windowRect;
    }
}