views:

124

answers:

2

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.

+2  A: 

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
Jørn Schou-Rode
+1 Thanks, that was the reflection I was after. I'm still sure there must be an easier way to find this out though!
Robin Day
+1, good answer. You have to go after the private field because using reflection on the Visible property still invokes the get accessor, subjecting you to whatever logic is in there. Although it would be highly unusual for an ASP.NET control to walk the control tree checking for visibility - it doesn't need to as its Render method is not invoked if its Visible property is false (which means any child controls automatically do not get rendered either).
slugster
@slugster: You say it is highly unusual to do so, but ASP.NET controls *do* walk the control tree when calling the getter on their `Visible` property. Run the test case shown in my answer against the `Visible` property, and you will get: false, false, false, true, true, false.
Jørn Schou-Rode
A: 

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

Please correct me if I am wrong.

Ravia