如何获取“可见性”属性的“真实”值?

15
如果将Windows窗体控件的Visible属性设置为true,则如果任何一个父窗口隐藏了,该属性仍然返回false。是否有办法在父窗口隐藏的情况下获取控件真正的可见性标志?
4个回答

17

正常的实现确实会检查控制堆栈,以确保所有父级都是可见的。我所知道的唯一规避此问题的方法是使用反射欺骗,并请求GetState(2),但这种方法很容易出错:

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

2是什么?有没有常量或枚举可以代替使用? - Jon B
1
@Jon,是的,有一个 - 但它本身是内部的,所以你需要使用更多的反射来获取它;-p 但它是STATE_VISIBLE。 - Marc Gravell

4

我所做的是暂时将按钮从其父控件中移除,以检查其 Visible 值,然后重新添加到父控件中。

如果需要,您可以跟踪子索引以在正确的索引处重新添加它。


2

我遇到了与派生自“ToolStripItem”基类的类相同的问题。因此,我使用了“Available”属性值来检查项目是否会显示。问题得到解决。样例:

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

在这个示例中,'curItm'是一个ToolStripItem派生类的实例。
在.Net控件中,依赖于父容器的Visible/Enabled属性的问题必须由.Net团队解决。我为自己的类创建了一个名为IsVisible/IsEnabled的自定义属性,该属性返回分配的Visible/Enabled属性的值,而不是依赖于父容器的值。

-1
一个不依赖于反射的选项是通过递归控件层次结构的父级,查找 Visible 属性设置为 false 的控件。 编辑:请参见代码的注释。

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


但这并不能告诉你原始值是真还是假;如果没有不可见的父级,你可以(大概)相信.Visible,但如果有,你就不知道你的控件是否具有(本地)Visible=true或Visible=false。 - Marc Gravell
您需要同时查看两者,因此如果当前可见,找到任何为false的父级将意味着它当前不是可见的。 - toad
但是如果任何父级不可见,Visible 就永远不会返回 true;这就是问题所在:框架已经检查过了。我认为 OP 想知道控件是否本地认为它是可见的,即如果所有父级都可见,它也会可见吗?你无法仅通过 Visible 找到这个答案。 - Marc Gravell
有趣的是,我没有看到它发生变化,因为我是基于VisibleChanged事件进行的,而当父控件的可见属性发生变化时,该事件并未触发。 - toad
猜测这是一个泄漏的抽象,将编辑帖子以展示我的意思。当父级被隐藏时,子项的VisibleChanged不会被触发,但当父级变为可见时,它会被触发。 - toad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接