How to get the set/real value of the Visible prope

2020-03-24 08:22发布

问题:

The Get of the Visible property of a control recursively looks up the tree to indicate if the control will be rendered or not.

I need a way to see what the "local" visible value of a control is regardless of what its parent controls are set to. i.e. Whether it itself was set to true or false.

I have seen this question, How to get the “real” value of the Visible property? which uses Reflection to obtain the local state, however, I have not been able to get this working for WebControls. It's also a rather dirty method of getting the value.

I have come up with the following extension method. It works by removing the control from its parent, checking the property, then putting the control back where it found it.

    public static bool LocalVisible(this Control control)
    {
        //Get a reference to the parent
        Control parent = control.Parent;
        //Find where in the parent the control is.
        int index = parent.Controls.IndexOf(control);
        //Remove the control from the parent.
        parent.Controls.Remove(control);
        //Store the visible state of the control now it has no parent.
        bool visible = control.Visible;
        //Add the control back where it was in the parent.
        parent.Controls.AddAt(index, control);
        //Return the stored visible value.
        return visible;
    }

Is this an acceptable way of doing this? It works fine and I haven't come across any performance issues. It just seems extremely dirty and I have no doubt there could be instances in which it might fail (for example, when actually rendering).

If anyone has any thoughts on this solution or better still a nicer way of finding the value then that would be great.

回答1:

After digging around a bit, I have produced the following extension method that uses reflection to retrieve the value of the Visible flag for classes inheriting from System.Web.UI.Control:

public static bool LocalVisible(this Control control)
{
    var flags = typeof (Control)
        .GetField("flags", BindingFlags.Instance | BindingFlags.NonPublic)
        .GetValue(control);

    return ! (bool) flags.GetType()
        .GetProperty("Item", BindingFlags.Instance | BindingFlags.NonPublic)
        .GetValue(flags, new object[] {0x10});
}

It uses reflection to find the private field flags within the Control object. This field is declared with an internal type, so more reflection is needed to invoke the getter of its indexer property.

The extension method has been tested on the following markup:

<asp:Panel Visible="false" runat="server">
    <asp:Literal ID="litA" runat="server" />
    <asp:Literal ID="litB" Visible="true" runat="server" />
    <asp:Literal ID="litC" Visible="false" runat="server" />
</asp:Panel>

<asp:Literal ID="litD" runat="server" />
<asp:Literal ID="litE" Visible="true" runat="server" />
<asp:Literal ID="litF" Visible="false" runat="server" />

Test results:

litA.LocalVisible() == true
litB.LocalVisible() == true
litC.LocalVisible() == false
litD.LocalVisible() == true
litE.LocalVisible() == true
litF.LocalVisible() == false


回答2:

You can expose the visiblility of controls using Property. This could solve your problem.

Please correct me if I am wrong.



回答3:

In case someone tries to get Jørn Schou-Rode's code working in VB.NET, here is the code that works for me. When I simply translate his code in VB, I get an "Ambiguous match found" exception, because there are 3 flavors of the flags "Item" property.

<Extension()>
Public Function GetLocalVisible(ctl As Control) As Boolean
    Dim flags As Object = GetType(Control).GetField("flags", BindingFlags.Instance Or BindingFlags.NonPublic).GetValue(ctl)
    Dim infos As PropertyInfo() = flags.GetType().GetProperties(BindingFlags.Instance Or BindingFlags.NonPublic)
    For Each info As PropertyInfo In infos
        If info.Name = "Item" AndAlso info.PropertyType.Name = "Boolean" Then
            Return Not CBool(info.GetValue(flags, New Object() {&H10}))
        End If
    Next
    Return ctl.Visible
End Function