Search code examples
asp.netuser-controlswebformsoverridingstack-overflow

ASP.NEt WebForms UserControl: Why is overriding .Visible causing a System.StackOverflowException?


I have a custom UserControl whose .Visible property I need to set to True or False. However, if the UserControl's first child control is a Panel and its ID is cMain, I want it to set the Panel's .Visible property instead of the UserControl's. Here's my code:

Here's the custom class I use:

Public MustInherit Class MyControl : Inherits UserControl

    Public Overrides Property Visible As Boolean
        Get
            Return GetVisible()
        End Get
        Set(value As Boolean)
            SetVisible(value)
        End Set
    End Property

    Function GetVisible() As Boolean

        Dim c As Control = GetMain()

        If TypeOf c Is Panel Then
            Return c.Visible
        Else
            Return MyBase.Visible
        End If

    End Function

    Sub SetVisible(Value As Boolean)

        Dim c As Control = GetMain()

        If TypeOf c Is Panel Then
            c.Visible = Value
        Else
            MyBase.Visible = Value
        End If

    End Sub

    Function GetMain() As Control

        Dim c As Control = If(Controls.Count = 0, Nothing, Controls(0))

        If Not (TypeOf c Is Panel AndAlso c.ID = "cMain") Then c = Me

        Return c

    End Function

End Class

Here's the actual UserControl itself:

<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="TestControl.ascx.vb" Inherits="JsonJqueryDevex.TestControl1" %>
<asp:Panel ID="cMain" runat="server">
inside
</asp:Panel>
outside

UserControl's codebehind:

Public Class TestControl1
    Inherits MyControl

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load


    End Sub

End Class

Here's the markup to implement it into the host page:

<uc:TestControl ID="ucTest" Visible="true" runat="server"></uc:TestControl>

Notice that I overrode .Visible within my base clase. I did this so that I could call MyBase if the control being referenced is the UserControl itself. Otherwise, I assume it's the Panel control. When I load the page, I get System.StackOverflowException. What's funny is that I don't get this when I have the custom control's Visible property set to false in the markup.

The stack trace shows that it's getting caught in .Visible's get accessor when it calls Return GetVisible(). If it's a Panel, it will execute Return c.Visible. However, as soon as I reference .Visible when c is a Panel, it breaks back into MyControl's .Visible get accessor. I don't know how this is possible since I am only overriding my custom control's Visible property, but it's acting as if I am overriding the Panel's .Visible property. What is going on here?


Solution

  • Your problem is with the behavior of Control.Visible.

    Your program is working when the value is false because it simply returns false at the point that it is checked. However, a control will not return true for .Visible unless both the control is visible and the parent is visible.

    What's happening in your case is that, when true, the parent is checking a child control for its .Visible value, and any child controls will check its parent (your user control) in addition to its own .Visible value. This is where your infinite recursion loop occurs, causing the stack overflow.