10

開いている WPF ウィンドウがデスクトップの接続されたモニターのいずれかに現在表示されているかどうかを判断する方法はありますか? 目に見えるとは、ウィンドウの境界の四角形が、いずれかのモニターのデスクトップの四角形と交差することを意味します。

アプリケーションの再起動時にモニター構成 (作業領域の境界、モニター数) が変更されたため (ウィンドウの位置が保存されます)、ウィンドウの位置を変更する必要があるかどうかを判断するには、この機能が必要です。

以下のコードを思いつきましたが、動作しているように見えますが、いくつかの問題があります。

  1. Windowsフォームを参照する必要があります。
  2. デスクトップの DPI 設定が必要で、Windows フォームの実際のピクセルを WPF 仮想ピクセルに変換します。
  3. 変換を実行するには、既にレンダリングされている実際の Visual インスタンスが必要です。

上記の 3 つの問題の一部またはすべてを解決するソリューションをご存知ですか?

using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media;

internal static class Desktop
{
    private static Size dpiFactor = new Size(1.0, 1.0);
    private static bool isInitialized;

    public static IEnumerable<Rect> WorkingAreas
    {
        get
        {
            return
                Screen.AllScreens.Select(
                    screen =>
                    new Rect(
                        screen.WorkingArea.Left * dpiFactor.Width,
                        screen.WorkingArea.Top * dpiFactor.Height,
                        screen.WorkingArea.Width * dpiFactor.Width,
                        screen.WorkingArea.Height * dpiFactor.Height));
        }
    }

    public static void TryInitialize(Visual visual)
    {
        if (isInitialized)
        {
            return;
        }

        var ps = PresentationSource.FromVisual(visual);
        if (ps == null)
        {
            return;
        }

        var ct = ps.CompositionTarget;
        if (ct == null)
        {
            return;
        }

        var m = ct.TransformToDevice;
        dpiFactor = new Size(m.M11, m.M22);
        isInitialized = true;
    }
}

(初期化された)Desktopクラスの使用法:

    private bool IsLocationValid(Rect windowRectangle)
    {
        foreach (var workingArea in Desktop.WorkingAreas)
        {
            var intersection = Rect.Intersect(windowRectangle, workingArea);
            var minVisible = new Size(10.0, 10.0);
            if (intersection.Width >= minVisible.Width && 
                intersection.Height >= minVisible.Height)
            {
                return true;
            }
        }

        return false;
    }

アップデート

SystemParameters.VirtualScreen*複数のモニターを使用する場合、「デスクトップ」は単純な長方形ではないため、仮想スクリーン ( ) の使用は機能しません。ポリゴンかもしれません。仮想画面に死角ができます。

  1. 接続された画面は異なる解像度を持つことができます
  2. 各画面の位置を設定できます。
4

3 に答える 3

8

同様のことを行うために使用するコードは、SystemParameters、特に SystemParameter.VirtualScreenLeft、Top、Width、および Height からの情報を使用します。

保存された Location と Size がある場合、ウィンドウが範囲外かどうかを次のように判断します。

bool outOfBounds =
    (location.X <= SystemParameters.VirtualScreenLeft - size.Width) ||
    (location.Y <= SystemParameters.VirtualScreenTop - size.Height) ||
    (SystemParameters.VirtualScreenLeft + 
        SystemParameters.VirtualScreenWidth <= location.X) ||
    (SystemParameters.VirtualScreenTop + 
        SystemParameters.VirtualScreenHeight <= location.Y);
于 2012-05-26T17:06:11.927 に答える
1

起動時に WPF プロジェクトで切り取ったこのコードを使用します。それはvb.netで書かれています:

If My.Settings.RememberWindowPositionAndSize Then
    If My.Settings.winMainWinState > 2 Then My.Settings.winMainWinState = WindowState.Normal
    If My.Settings.winMainWinState = WindowState.Minimized Then My.Settings.winMainWinState = WindowState.Normal
    Me.WindowState = My.Settings.winMainWinState
    If My.Settings.winMainWinState = WindowState.Normal Then
        Dim winBounds As New System.Drawing.Rectangle(CInt(My.Settings.winMainPosX), CInt(My.Settings.winMainPosY),
                                                      CInt(My.Settings.winMainSizeB), CInt(My.Settings.winMainSizeH))
        For Each scr As System.Windows.Forms.Screen In System.Windows.Forms.Screen.AllScreens
            If winBounds.IntersectsWith(scr.Bounds) Then
                Me.Width = My.Settings.winMainSizeB
                Me.Height = My.Settings.winMainSizeH
                Me.Top = My.Settings.winMainPosY
                Me.Left = My.Settings.winMainPosX
                Exit For
            End If
        Next
    End If
End If

そして、これはC#の同じ(変換された)コードです

if (My.Settings.RememberWindowPositionAndSize) {
    if (My.Settings.winMainWinState > 2)
        My.Settings.winMainWinState = WindowState.Normal;
    if (My.Settings.winMainWinState == WindowState.Minimized)
        My.Settings.winMainWinState = WindowState.Normal;
    this.WindowState = My.Settings.winMainWinState;

    if (My.Settings.winMainWinState == WindowState.Normal) {
        System.Drawing.Rectangle winBounds = new System.Drawing.Rectangle(Convert.ToInt32(My.Settings.winMainPosX), Convert.ToInt32(My.Settings.winMainPosY), Convert.ToInt32(My.Settings.winMainSizeB), Convert.ToInt32(My.Settings.winMainSizeH));

        foreach (System.Windows.Forms.Screen scr in System.Windows.Forms.Screen.AllScreens) {
            if (winBounds.IntersectsWith(scr.Bounds)) {
                this.Width = My.Settings.winMainSizeB;
                this.Height = My.Settings.winMainSizeH;
                this.Top = My.Settings.winMainPosY;
                this.Left = My.Settings.winMainPosX;
                break;
            }
        }
    }
}
于 2017-07-20T13:35:50.317 に答える
-1

このコードは、ウィンドウの左上隅が仮想画面ボックス (使用可能なすべての画面を含む四角形) 内にあるかどうかを確認します。また、プライマリ モニターが右側または下部にあるなど、座標が負になる可能性があるマルチモニターのセットアップも処理します。

bool valid_position =
SystemParameters.VirtualScreenLeft <= saved_location.X &&
(SystemParameters.VirtualScreenLeft + SystemParameters.VirtualScreenWidth) >= saved_location.X &&
SystemParameters.VirtualScreenTop <= saved_location.Y &&
(SystemParameters.VirtualScreenTop + SystemParameters.VirtualScreenHeight) >= saved_location.Y;
于 2016-12-21T12:58:27.707 に答える