Question

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?

Was it helpful?

Solution

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

OTHER TIPS

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.

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

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top