15

If you set the Visible property of a Windows Forms control to true, that property still returns false if any of the control's parent windows are hidden. Is there a way to get the true, underlying visibility flag of the control in case the parent window is hidden?

Qwertie
  • 16,354
  • 20
  • 105
  • 148

4 Answers4

17

Well, the regular implementation does check up the control stack, to ensure that all parents are visible. The only way I know to dodge this is to cheat with reflection, and ask for GetState(2), but that is brittle:

    // dodgy; not recommended
    Panel query;
    Form form = new Form
    {
        Controls = {
            new Panel {
                Visible = false,
                Controls = {
                    (query = new Panel {Visible = true})
                }
            }
        }
    };
    form.Show();

    // this is the dodgy bit...
    bool visible = (bool)typeof(Control)
        .GetMethod("GetState", BindingFlags.Instance | BindingFlags.NonPublic)
        .Invoke(query, new object[] { 2 });
BigBoss
  • 6,904
  • 2
  • 23
  • 38
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
4

What I did is temporarily remove the button from its parent controls to check its Visible value and then re-add to the parent controls.

If you need you can track the child index to re-add it at the right index.

Tuan-Tu
  • 73
  • 5
2

I have same issue with classes derived from 'ToolStripItem' base class. so I used Available property value to check if item will be displayed or not. problem solved. Sample:

ToolStripItem curItm = menuStrip1.Items[i] as ToolStripItem;
if(curItm is ToolStripItem && curItm.Available) DoAnyThing();

In this sample 'curItm' is an instance of of ToolStripItem derived class.

This problem with Visible/Enabled properties in .Net controls that depend on parent container's Visible/Enabled must be solved by .Net team. I create a costume property named IsVisible/IsEnabled in my own classes that return assigned value for Visible/Enabled properties and not the value that depend on parent container.

-1

An option that doesn't rely on reflection would be to recurse through the parents of the control hierarchy looking for one with Visible set to false.

EDIT: See comments for significance of code.

var frm2 = new Form {Text = "Form2"};
var lbl = new Label {Visible = true};
frm2.Controls.Add(lbl);
frm2.Show();

var frm1 = new Form {Text = "Form1"};
var lblVis = new Label { Text = lbl.Visible.ToString(), Left = 10, Top = 10};
lbl.VisibleChanged += (sender, args) => MessageBox.Show("Label Visible changed");
var btnShow = new Button {Text = "Show", Left = 10, Top = lblVis.Bottom + 10};
btnShow.Click += (sender, args) =>
                    {
                        frm2.Visible = true;
                        lblVis.Text = lbl.Visible.ToString();
                        };
var btnHide = new Button {Text = "Hide", Left = 10, Top = btnShow.Bottom + 10};
btnHide.Click += (sender, args) =>
                    {
                        frm2.Visible = false;
                        lblVis.Text = lbl.Visible.ToString();
                    };

frm1.Controls.AddRange(new Control[] {lblVis, btnShow, btnHide});

Application.Run(frm1);

toad
  • 1,351
  • 8
  • 14
  • But that doesn't tell you whether the original is true or false; if there are no invisible parents, you can (probably) trust .Visible, but if there *are*, you have no clue whether your control has (locally) Visible=true or Visible=false – Marc Gravell Dec 24 '08 at 17:51
  • You would have to look at both, so if currently visible finding any parent that is false would mean it isn't currently. – toad Dec 24 '08 at 18:03
  • But Visible will never return true if any parent is invisible; that is the problem: the framework already checks this. I think the OP wants to know whether the control *locally* thinks it is visible, i.e. if all parents were visible, would it be too? You can't find this just by Visible. – Marc Gravell Dec 24 '08 at 18:06
  • Interesting, was not seeing it change because I was basing it off of the VisibleChanged event which was not firing when the parent controls visible property was changing. – toad Dec 24 '08 at 18:27
  • Guess this is a leaky abstraction, will edit post to put some code showing what I mean. When the parent is hidden a childs VisibleChanged is not fired, but when the parent is made Visible it is. – toad Dec 24 '08 at 18:33