Hej, Jag fick förklaring av författaren till artikeln jag refererade till.Dynamiskt laddade UserControls och PostBacks
Jag har länge brottats med problem gällande ViewState, PostBacks och UserControls. Det grundläggande problemet är att när jag lägger till en UserControl programmatiskt, måste jag re-adda den vid varje postback. Detta medför två nackdelar:
1) Jag måste hålla reda på vilken kontroll som är laddad via en egen variabel i tex ViewState()
2) Kontrollen som ska "unloadas" laddas upp (och logiken körs) även då den ska tas bort i nästa eventhandler
För att visa detta bättre använder jag följande kärnexempel:
'En basklass som alla mina usercontrols ärver från
Imports Microsoft.VisualBasic
Namespace My.CustomBaseLayer
Public Class CustomUserControl
Inherits UserControl
Public Event OnPageLoad(ByVal sender As Object, ByVal e As EventArgs)
Public Event OnPostBack(ByVal sender As Object, ByVal e As EventArgs)
Private Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If ViewState("IsPostBack") = "" Then
ViewState("IsPostBack") = "True"
RaiseEvent OnPageLoad(sender, e)
ElseIf ViewState("IsPostBack") = "True" Then
RaiseEvent OnPostBack(sender, e)
End If
End Sub
End Class
End Namespace
'En userControl som binder spelarstatistik till en repeater (notera OnPostBack event handlern)
Imports My.DataAccessLayer
Imports My.CustomBaseLayer
Partial Class UserControls_Player
Inherits CustomUserControl
Protected Sub Page_OnPageLoad(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.OnPageLoad
'Binder playerstatistics
repPlayerStatistics.DataSource = tPlayerStatistics.GetPlayerStatistics()
repPlayerStatistics.DataBind()
End Sub
Protected Sub Page_OnPostBack(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.OnPostBack
'ponera att det körs en massa logik här
End Sub
End Class
'Och såhär ser codebehind ut till ASPX-sidan där en PlaceHolder för usercontrols finns
Imports My.DataAccessLayer
Partial Class Statistics
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
lnkSwitchView_Click(sender, e)
End If
End Sub
Private Sub AddControl(ByVal ControlPath As String)
Dim insControl As Control = LoadControl(ControlPath)
insControl.ID = Replace(insControl.TemplateControl.ToString, "ASP.", "")
ViewState("ControlPath") = ControlPath
phUserControl.Controls.Clear()
phUserControl.Controls.Add(insControl)
End Sub
Protected Sub lnkSwitchView_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles lnkSwitchView.Click
If lnkSwitchView.Text = "Switch to Clan Statistics" Then
lHeader.Text = "Clan Statistics"
AddControl("UserControls/Statistics/Clan.ascx")
lnkSwitchView.Text = "Switch to Player Statistics"
Else
lHeader.Text = "Player Statistics"
AddControl("UserControls/Statistics/Player.ascx")
lnkSwitchView.Text = "Switch to Clan Statistics"
End If
End Sub
Protected Overrides Sub LoadViewState(ByVal savedState As Object)
MyBase.LoadViewState(savedState)
If ViewState("ControlPath") <> "" Then
AddControl(ViewState("ControlPath"))
End If
End Sub
End Class
Om vi nu följer stacken:
Sidan laddas, är inte en postback, eventhandlern lnkSwitchView_Click körs programmatiskt. Kontrollen "Player Statistics" läggs till eftersom (lnkSwitchView.Text = "Switch to Clan Statistics") = False (Else körs).
Nu vill användaren istället se klanstatistik, och trycker därför på knappen vilket gör att sidan postbackas. Sidans LoadViewState() körs, den hittar en ControlPath (eftersom denna lades till i ViewStaten när kontrollen addades första gången), laddar in kontrollen. Enligt min CustomUserControl är kontrollen nu en PostBack eftersom ViewState("IsPostBack") = "True", alltså körs subben där jag skrev kommentaren "här körs en massa logik". SEDAN kommer vi till eventhandlern lnkSwitchView_Click! Nu (efter att den har gjort allt jobbet med logiken i den "gamla" kontrollen) rensas PlaceHoldern och rätt kontroll läggs till. Enligt min CustomUserControl är denna kontroll ingen postback, och OnPageLoad() körs.
Problematiken här är dels att webbservern gör onödigt jobb med kontrollen som egentligen ska bort. Jag tycker också att lösningen är onödigt krånglig (varför kan inte Me.IsPostBack i kontrollen verkligen visa om KONTROLLEN laddas för första gången. Den visar om SIDAN laddas för första gången.) och jag tycker inte att jag borde behöva bygga en basklass för usercontrols bara för att få den här (grundläggande) funktionaliteten.
Har jag fått allt om bakfoten? Kan någon kasta ljus över det här problemet?
För er som vill läsa mer om hur ViewState fungerar kan jag rekommendera den här artikeln: http://infinitiesloop.blogspot.com/2006/03/truly-understanding-viewstate.html
Sv: Dynamiskt laddade UserControls och PostBacks
Länken till artikeln finns ovan för de som är intresserade.