asp.net FindControl Recursively

依然范特西╮ 提交于 2019-11-29 14:31:35

Why don't you simply expose properties that return PH1 and PH2, because the master has the reference of them and you don't need to iterate all child controls of master:

Public ReadOnly Property Container1 As PlaceHolder
    Get
        Return Me.PH1
    End Get
End Property

Public ReadOnly Property Container2 As PlaceHolder
    Get
        Return Me.PH2
    End Get
End Property

You can access them:

Dim ph1 As PlaceHolder = DirectCast(Me.Master, myMaster).Container1
Dim ph2 As PlaceHolder = DirectCast(Me.Master, myMaster).Container2

Another problem is this line:

controlInstance1.ID = "control_2"

You are setting only controlInstance1's ID twice, but that doesn't cause your issue.

Your main problem is that you are adding the controls to the placeholders in Page_Init instead of Page_Load. Therefore the UserControls can't load their ViewState and the ListView is empty. Recreate them in Page_Load and it will work.

Edit: But i must admit that i don't know why your iterate extension wins over the recursive. The reference on the placeholders are the same, they shouldn't work both, weird.

summary:

  • it works with my properties,
  • putting all in page's load event handler instead init
  • with your iterate-extension(for whatever reasons)

It also works if you add both UserControls at last, after you've found the placeholders via FindControlRecursively.

zone.Controls.Add(controlInstance1)
zone2.Controls.Add(controlInstance2)

I'm losing motivation on this, but i'm sure you'll find the answer here. Controls.Add loads it's parent's ViewState into all childs and therefore it depends on when you add the controls, also the index of the controls in their parent controls must be the same on postback to reload the ViewState.

Your recursive extension method touches control1's ID after you've added it to PH1(while searching PH2), the iterative extension does not. I assume that this corrupts it's ViewState in Page_Init.

Conclusion Use properties instead

I figured out why I was seeing the behavior I described above. I changed the recursive function to the following:

<Extension()> _
    Public Function FindControlRecursively(ByVal parentControl As System.Web.UI.Control, ByVal controlId As String) As System.Web.UI.Control

        If String.IsNullOrEmpty(controlId) = True OrElse controlId = String.Empty Then
            Return Nothing
        End If

        If parentControl.ID = controlId Then
            Return parentControl
        End If

        If parentControl.HasControls Then
            For Each c As System.Web.UI.Control In parentControl.Controls
                Dim child As System.Web.UI.Control = FindControlRecursively(c, controlId)
                If child IsNot Nothing Then
                    Return child
                End If
            Next
        End If

        Return Nothing

    End Function

By adding the parentControl.HasControls check, I am preventing the function from searching the listview for child controls, and this allows the listview to load its viewstate later on in the page/control lifecycle.

Also, I tweaked my iterative function to make it more efficient and prevent it from bugging out if a control was not returned:

<Extension()> _
    Public Function FindControlIteratively(ByVal parentControl As Web.UI.Control, ByVal controlId As String) As Web.UI.Control

        Dim ll As New LinkedList(Of Web.UI.Control)

        While parentControl IsNot Nothing
            If parentControl.ID = controlId Then
                Return parentControl
            End If
            For Each child As Web.UI.Control In parentControl.Controls
                If child.ID = controlId Then
                    Return child
                End If
                If child.HasControls() Then
                    ll.AddLast(child)
                End If
            Next
            If (ll.Count > 0) Then
                parentControl = ll.First.Value
                ll.Remove(parentControl)
            Else
                parentControl = Nothing
            End If
        End While

        Return Nothing

    End Function

Also, to follow up on my earlier description of the problem - I was able to reproduce the recursive function's intially weird behavior using the iterative function if I removed the If child.HasControls() Then check from the iterative function. Hope that makes sense.

In the end I am sticking with the iterative function because looping should be less expensive than recursion, though in real world scenarios the difference probably will not be noticeable.

The following links were extremely helpful to me in working this out:

http://msdn.microsoft.com/en-us/library/ms972976.aspx#viewstate_topic4

http://www.4guysfromrolla.com/articles/092904-1.aspx

http://scottonwriting.net/sowblog/archive/2004/10/06/162995.aspx

http://scottonwriting.net/sowblog/archive/2004/10/08/162998.aspx

Extra thanks to Tim for pointing me in the right direction.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!