Подтвердить что ты не робот

С# winform проверяет, является ли управление физически видимым

Можно ли определить, видно ли хотя бы один пиксель элемента управления (с помощью свойства или, возможно, с помощью уведомления о событиях).

NB: я не ищу свойство Visible, которое может вернуть true, даже если другое окно скрывает элемент управления

4b9b3361

Ответ 1

Вы можете аннулировать элемент управления, а затем вызвать GetUpdateRect (функция Win32 api), чтобы узнать об этом. Однако у него есть побочный эффект, вызвавший перерисовку.

Ответ 2

Прагматичным решением является использование метода GetChildAtPoint(), передающего 4 угла элемента управления. Если один из них возвращает значение 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;
}

Ответ 3

Чтобы облегчить предыдущий ответ на ваш вопрос.

Вот исходный код, который вам нужно будет использовать с GetUpdateRect как jdv Сказал Ян де Ваан.

[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
}

Удачи.

Ответ 4

Если элемент управления виден, событие Paint будет вызываться (повторно).

Обычно для невидимых элементов управления это событие не будет вызываться.

Ответ 5

Вдохновленный Хансом ответ, я реализовал это поведение таким образом;

    [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;
    }

Ответ 6

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

Например, скажем, что есть GroupBox внутри TabPage.

Когда соответствующая вкладка будет нажата, событие макета будет запускаться для первой вкладки, а затем для GroupBox

Вы можете использовать его в сочетании с свойством видимости

Ответ 7

Вы можете проверить видимость родительского элемента управления.

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

Ответ 8

Я несколько закончил ответ Хансом Пассантом. Функция ниже тестов для всех четырех углов формы.

        /// <summary>
    /// determines if a form is on top and really visible.
    /// a problem you ran into is that form.invalidate returns true, even if another form is on top of it. 
    /// this function avoids that situation
    /// code and discussion:
    /// https://stackoverflow.com/info/4747935/c-sharp-winform-check-if-control-is-physicaly-visible
    /// </summary>
    /// <param name="child"></param>
    /// <returns></returns>
    public bool ChildReallyVisible(Control child)
    {
        bool result = false;

        var pos = this.PointToClient(child.PointToScreen(Point.Empty));

        result = this.GetChildAtPoint(pos) == child;
        //this 'if cause the condition only to be checked if the result is true, otherwise it will stay false to the end
        if(result)
        {
            result = (this.GetChildAtPoint(new Point(pos.X + child.Width - 1, pos.Y)) == child);
        }
        if(result)
        {
            result = (this.GetChildAtPoint(new Point(pos.X, pos.Y + child.Height - 1)) == child);
        }
        if(result)
        {
            result = (this.GetChildAtPoint(new Point(pos.X + child.Width - 1, pos.Y + child.Height - 1)) == child) ;
        }
        return result;
    }