Как я могу проверить, что окно полностью видно на экране пользователя? - PullRequest
11 голосов
/ 06 июля 2011

Есть ли способ проверить, что WinForm полностью виден на экране (например, не выходит за пределы экрана?)

Я пытался использовать SystemInformation.VirtualScreen для этого, который прекрасно работаетпока виртуальный экран является прямоугольником, но как только это не так (например, 3 экрана в форме буквы L), SystemInformation.VirtualScreen возвращает наименьший прямоугольник, содержащий все видимые пиксели (поэтому окно в верхнем правом углу Lне будет виден, хотя находится на виртуальном экране)


Причина, по которой я пытаюсь это сделать, заключается в том, что я хотел бы, чтобы моя программа открывала дочерние окна в последнем месте, где они были, но я не хочу, чтобы это окно было вне поля зрения, если пользователь изменяет настройки (например, отключает дополнительный экран от своего ноутбука)

Ответы [ 5 ]

11 голосов
/ 18 июля 2011

Вот как я в итоге это сделал:

bool isPointVisibleOnAScreen(Point p)
{
    foreach (Screen s in Screen.AllScreens)
    {
        if (p.X < s.Bounds.Right && p.X > s.Bounds.Left && p.Y > s.Bounds.Top && p.Y < s.Bounds.Bottom)
            return true;
    }
    return false;
}

bool isFormFullyVisible(Form f)
{
    return isPointVisibleOnAScreen(new Point(f.Left, f.Top)) && isPointVisibleOnAScreen(new Point(f.Right, f.Top)) && isPointVisibleOnAScreen(new Point(f.Left, f.Bottom)) && isPointVisibleOnAScreen(new Point(f.Right, f.Bottom));
 }

Могут быть некоторые ложные срабатывания, если у пользователя есть «дыра» в его настройке дисплея (см. Пример ниже), но я не думаю, что кто-либо из моих пользователей когда-либо будет в такой ситуации:)

   [1]
[2][X][3]
4 голосов
/ 06 июля 2011

Вот как бы я это сделал:

Это сместит элемент управления (форму) внутри границ дисплея как можно ближе к исходному местоположению.

    private void EnsureVisible(Control ctrl)
    {
        Rectangle ctrlRect = ctrl.DisplayRectangle; //The dimensions of the ctrl
        ctrlRect.Y = ctrl.Top; //Add in the real Top and Left Vals
        ctrlRect.X = ctrl.Left;
        Rectangle screenRect = Screen.GetWorkingArea(ctrl); //The Working Area fo the screen showing most of the Ctrl

        //Now tweak the ctrl's Top and Left until it's fully visible. 
        ctrl.Left += Math.Min(0, screenRect.Left + screenRect.Width - ctrl.Left - ctrl.Width);
        ctrl.Left -= Math.Min(0, ctrl.Left - screenRect.Left);
        ctrl.Top += Math.Min(0, screenRect.Top + screenRect.Height - ctrl.Top - ctrl.Height);
        ctrl.Top -= Math.Min(0, ctrl.Top - screenRect.Top);

    }

Конечно, чтобы ответить на исходный вопрос, вместо перемещения элемента управления, вы можете просто проверить, не вернул ли какой-либо из 4 Math.Min что-либо кроме 0.

3 голосов
/ 06 июля 2011

Проверьте, есть ли Screen.AllScreens.Any(s => s.WorkingArea.Contains(rect))

2 голосов
/ 23 апреля 2015

Это моё решение. Это решает проблему "дыры".

    /// <summary>
    /// True if a window is completely visible 
    /// </summary>
    static bool WindowAllVisible(Rectangle windowRectangle)
    {
        int areaOfWindow = windowRectangle.Width * windowRectangle.Height;
        int areaVisible = 0;
        foreach (Screen screen in Screen.AllScreens)
        {
            Rectangle windowPortionOnScreen = screen.WorkingArea;
            windowPortionOnScreen.Intersect(windowRectangle);
            areaVisible += windowPortionOnScreen.Width * windowPortionOnScreen.Height;
            if (areaVisible >= areaOfWindow)
            {
                return true;
            }
        }
        return false;
    }
2 голосов
/ 19 февраля 2015

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

Поэтому я взял на себя задачу создать свой собственный класс, который будет заниматься именно этим и работает на 100%.

Вот мой код

public static class ScreenOperations
{
    public static bool IsWindowOnAnyScreen(Window Window, short WindowSizeX, short WindowSizeY, bool AutoAdjustWindow)
    {
        var Screen = System.Windows.Forms.Screen.FromHandle(new WindowInteropHelper(Window).Handle);

        bool LeftSideTest = false, TopSideTest = false, BottomSideTest = false, RightSideTest = false;

        if (Window.Left >= Screen.WorkingArea.Left)
            LeftSideTest = true;

        if (Window.Top >= Screen.WorkingArea.Top)
            TopSideTest = true;

        if ((Window.Top + WindowSizeY) <= Screen.WorkingArea.Bottom)
            BottomSideTest = true;

        if ((Window.Left + WindowSizeX) <= Screen.WorkingArea.Right)
            RightSideTest = true;

        if (LeftSideTest && TopSideTest && BottomSideTest && RightSideTest)
            return true;
        else
        {
            if (AutoAdjustWindow)
            {
                if (!LeftSideTest)
                    Window.Left = Window.Left - (Window.Left - Screen.WorkingArea.Left);

                if (!TopSideTest)
                    Window.Top = Window.Top - (Window.Top - Screen.WorkingArea.Top);

                if (!BottomSideTest)
                    Window.Top = Window.Top - ((Window.Top + WindowSizeY) - Screen.WorkingArea.Bottom);

                if (!RightSideTest)
                    Window.Left = Window.Left - ((Window.Left + WindowSizeX) - Screen.WorkingArea.Right);
            }
        }

        return false;
    }
}

Использование: ScreenOperations.IsWindowOnAnyScreen(WPFWindow, WPFWindowSizeX, WPFWindowSizeY, true); это проверит, если окно вообще за кадром, то есть 1 пиксель под панелью задач или 1 пиксель от текущего монитора пользователя.

Он определяет, какой монитор окно, если на первом, поэтому он должен работать с несколькими мониторами.

этот метод возвращает истину, если окно на экране и ложь, если это не так.

ПоследнийПараметр для автоматической настройки окна до ближайшей части экрана для вас.если вы установите false для этого параметра, он не будет настраивать окно для вас.

Так что это полное решение WPF для этой проблемы, и преобразование WinForm должно быть простым, если вы знаете, как это сделать, измените окно наФорма и FromHandle(Form.Handle) должны работать.

...