C# winform check if control is physicaly visible

后端 未结 9 1615
有刺的猬
有刺的猬 2020-12-09 01:58

Is it possible to determine if at least one pixel of a control can be seen (by a property or maybe using event notification).

NB : I am not looking for the Visible p

相关标签:
9条回答
  • 2020-12-09 02:35

    Inspired by Hans's answer I've implemented this behavior in this way;

        [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;
        }
    
    0 讨论(0)
  • 2020-12-09 02:35

    In order to facilitate a previous answer to your question.

    Here is the source code that you will need to work with the GetUpdateRect function as jdv-Jan de Vaan answered.

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

    When you need to check if a specified is visible just do something like the following:

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

    Good luck.

    0 讨论(0)
  • 2020-12-09 02:38

    A pragmatic solution is to use the form's GetChildAtPoint() method, passing the 4 corners of the control. If one of them returns true then the control is definitely visible. It is not 100% reliable, all 4 corners could be overlapped by another control but still leave part of interior visible. I would not worry about that, too bizarre.

    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;
    }
    
    0 讨论(0)
  • 2020-12-09 02:44

    You may use Layout event of controls. it is triggered when control comes to screen and tries to layout its child controls.

    For example, let's say there is GroupBox inside a TabPage.
    When relevant tab clicked, layout event will fire for first tabpage then for GroupBox
    You may use it combined with visibility property

    0 讨论(0)
  • 2020-12-09 02:48

    You can invalidate the control and then call GetUpdateRect (Win32 api function) to find this out. It does have the side effect of causing a repaint, though.

    0 讨论(0)
  • 2020-12-09 02:49

    You can check for visibility of parent control.

        protected override void OnParentVisibleChanged(EventArgs e)
        {
            base.OnParentVisibleChanged(e);
            isVisible = true;
        }
    
    0 讨论(0)
提交回复
热议问题