Как получить "реальное" значение свойства Visible?

Если вы установите для свойства Visible элемента управления Windows Forms значение true, это свойство все равно возвращает false, если какое-либо из окон родительского контроля скрыто. Есть ли способ получить истинный, базовый флаг видимости элемента управления в случае скрытия родительского окна?

Ответ 1

Ну, регулярная реализация проверяет контрольный стек, чтобы убедиться, что все родители видны. Единственный способ, которым я знаю, это увернуться от этого - обмануть с отражением и просить 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

Что я сделал, это временно удалить кнопку из своих родительских элементов управления, чтобы проверить ее видимое значение, а затем повторно добавить к родительским элементам управления.

Если вам нужно, вы можете отслеживать дочерний индекс, чтобы повторно добавить его в нужный индекс.

Ответ 3

Опция, которая не полагается на рефлексию, должна состоять в том, чтобы возвратить родителям иерархии управления, ища одно значение с видимым значением в false.

EDIT: См. комментарии для значимости кода.

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

Ответ 4

У меня такая же проблема с классами, полученными из базового класса ToolStripItem. поэтому я использовал значение Available property, чтобы проверить, будет ли элемент отображаться или нет. задача решена. Пример:

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

В этом примере "curItm" является экземпляром производного класса ToolStripItem.

Эта проблема с свойствами Visible/Enabled в элементах .Net, которые зависят от родительского контейнера Visible/Enabled, должна быть решена командой .Net. Я создаю свойство costume с именем IsVisible/IsEnabled в моих собственных классах, которые возвращают назначенное значение для свойств Visible/Enabled, а не значение, зависящее от родительского контейнера.