How to get the “real” value of the Visible property?

倾然丶 夕夏残阳落幕 提交于 2019-12-05 01:03:39
Marc Gravell

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

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!