web-dev-qa-db-ja.com

C#winformは、コントロールが物理的に表示されているかどうかを確認します

コントロールの少なくとも1つのピクセルが表示されるかどうかを判断することは可能ですか(プロパティによって、またはイベント通知を使用して)。

注意:他のウィンドウがコントロールを非表示にしている場合でもtrueを返すことができるVisibleプロパティを探していません

28
Toto

コントロールを無効にしてから GetUpdateRect (Win32 api関数)を呼び出してこれを見つけることができます。ただし、再描画を引き起こすという副作用があります。

7
user180326

実用的な解決策は、フォームのGetChildAtPoint()メソッドを使用して、コントロールの4つのコーナーを渡すことです。それらの1つがtrueを返す場合、コントロールは確実に表示されます。 100%信頼できるわけではなく、4つのコーナーすべてが別のコントロールによってオーバーラップする可能性がありますが、それでも内部の一部は表示されたままになります。私はそれについて心配しません、あまりにも奇妙です。

public bool ChildReallyVisible(Control child) {
    var pos = this.PointToClient(child.PointToScreen(Point.Empty));

    //Test the top left
    if (this.GetChildAtPoint(pos) == child) return true;

    //Test the top right
    if (this.GetChildAtPoint(new Point(pos.X + child.Width - 1, pos.Y)) == child) return true;

    //Test the bottom left
    if (this.GetChildAtPoint(new Point(pos.X, pos.Y + child.Height -1)) == child) return true;

    //Test the bottom right
    if (this.GetChildAtPoint(new Point(pos.X + child.Width - 1, pos.Y + child.Height -1)) == child) return true;

    return false;
}
15
Hans Passant

あなたの質問への前の answer を容易にするために。

GetUpdateRect 関数を使用して作業する必要があるソースコードは次のとおりです jdv-Jan de Vaan 回答済み。

[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
internal struct RECT
{
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;
    public int Width { get { return this.Right - this.Left; } }
    public int Height { get { return this.Bottom - this.Top; } }
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
internal static extern bool GetUpdateRect(IntPtr hWnd, ref RECT rect, bool bErase);
public static bool IsControlVisibleToUser(Control control)
{
    control.Invalidate();
    Rectangle bounds = control.Bounds;
    RECT rect = new RECT { Left = bounds.Left, Right = bounds.Right, Top = bounds.Top, Bottom = bounds.Bottom };
    return GetUpdateRect(control.Handle, ref rect, false);
}

指定が表示されているかどうかを確認する必要がある場合は、次のようにします。

if (IsControlVisibleToUser(controlName) == true)
{
    // The Specified Control is visible.
    // ... do something 
}
else
{
    // Control is not visible.
    // ... do something else
}

幸運を。

5
Fábio Antunes

ハンスの答えに触発されて、私はこの振る舞いをこのように実装しました。

    [DllImport("user32.dll")]
    static extern IntPtr WindowFromPoint(POINT Point);

    [StructLayout(LayoutKind.Sequential)]
    public struct POINT
    {
        public int X;
        public int Y;

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

        public static implicit operator System.Drawing.Point(POINT p)
        {
            return new System.Drawing.Point(p.X, p.Y);
        }

        public static implicit operator POINT(System.Drawing.Point p)
        {
            return new POINT(p.X, p.Y);
        }
    }

    public static bool IsControlVisibleToUser(this Control control)
    {
        var pos = control.PointToScreen(control.Location);
        var pointsToCheck = new POINT[]
                                {
                                    pos,
                                    new Point(pos.X + control.Width - 1, pos.Y),
                                    new Point(pos.X, pos.Y + control.Height - 1),
                                    new Point(pos.X + control.Width - 1, pos.Y + control.Height - 1),
                                    new Point(pos.X + control.Width/2, pos.Y + control.Height/2)
                                };

        foreach (var p in pointsToCheck)
        {
            var hwnd = WindowFromPoint(p);
            var other = Control.FromChildHandle(hwnd);
            if (other == null)
                continue;

            if (control == other || control.Contains(other))
                return true;
        }

        return false;
    }
3
Sebastian Piu

コントロールが表示されている場合、Paintイベントが(繰り返し)呼び出されます。

通常、表示されていないコントロールの場合、このイベントは呼び出されません。

3
GvS

上記を試しましたが、winformが別のアプリでカバーされていても真になり続けました。

(私のwinformクラス内で)以下を使用することになりました:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace yourNameSpace
{
    public class Myform : Form
    {

        private void someFuncInvokedByTimerOnMainThread()
        {
            bool isVisible = isControlVisible(this);
            // do something.
        }

        [DllImport("user32.dll")]
        static extern IntPtr WindowFromPoint(System.Drawing.Point p);


        ///<summary><para>------------------------------------------------------------------------------------</para>
        ///
        ///<para>           Returns true if the control is visible on screen, false otherwise.                </para>
        ///
        ///<para>------------------------------------------------------------------------------------</para></summary>
        private bool isControlVisible(Control control)
        {
            bool result = false;
            if (control != null)
            {
                var pos = control.PointToScreen(System.Drawing.Point.Empty);
                var handle = WindowFromPoint(new System.Drawing.Point(pos.X + 10, pos.Y + 10)); // +10 to disregard padding   
                result = (control.Handle == handle); // should be equal if control is visible
            }
            return result;
        }
    }
}
1
Shai Volvovsky

親コントロールの可視性を確認できます。

    protected override void OnParentVisibleChanged(EventArgs e)
    {
        base.OnParentVisibleChanged(e);
        isVisible = true;
    }
0
Track

コントロールのレイアウトイベントを使用できます。コントロールが画面に表示され、子コントロールをレイアウトしようとするとトリガーされます。

たとえば、TabPage内にGroupBoxがあるとします。
関連するタブがクリックされると、レイアウトイベントが最初のタブページで発生し、次にGroupBoxで発生します
可視性プロパティと組み合わせて使用​​できます

0
Add080bbA