I know there are several posts on this topic, but the common answer seems to be, "Make sure all docks are created in the Page_Init" event. As far as I can tell, I've done that. (Using a modified implementation of the Portal example.)
Config is saved to the database as part of the CurrentDockStates property.
I hate to post a mountain of code, but I'm pretty much stuck.
The viewstate error occurs without any real regularity, but once it starts, it doesn't seem to stop until I reset all the docks. It seems to happen most often after deleting a dock.
Many of my docks contain forms, some have timers, their own update panels, etc. I'm guessing that turning off viewstate is not an option...?
| Imports System |
| Imports System.Collections |
| Imports System.Collections.Generic |
| Imports System.ComponentModel |
| Imports System.Data |
| Imports System.Drawing |
| Imports System.Web |
| Imports System.Web.SessionState |
| Imports System.Web.UI |
| Imports System.Web.UI.WebControls |
| Imports System.Web.UI.HtmlControls |
| Imports Telerik.Web.UI |
| Imports UserFunctions |
| Imports Messages |
| Imports Permissions |
| Namespace Telerik.Web.Examples.Dock.MyPortal |
| Partial Public Class DefaultVB |
| Inherits System.Web.UI.Page |
| Private Property CurrentDockStates() As List(Of DockState) |
| Get |
| Dim _currentDockStates As List(Of DockState) = DirectCast(Session("UserPreferences.PortalSession"), List(Of DockState)) |
| If [Object].Equals(_currentDockStates, Nothing) Then |
| 'Make an empty configuration list |
| _currentDockStates = New List(Of DockState)() |
| 'Convert our stored config to the active config |
| Dim strLoadedConfig As String = GetUserPreference("PortalConfiguration") |
| 'If we found nothing, leave the current state empty |
| If strLoadedConfig <> "" Then |
| Try |
| 'Use the stored config |
| 'Convert the stored config to an array, splitting at the *s |
| Dim aConfig As Array = Split(strLoadedConfig, "*") |
| Dim strConfigItem As String |
| Dim dsWorking As DockState |
| 'Parse through the array, turning the dockstate strings into dockstates |
| 'Then add the dockstates to the dockstate list |
| For Each strConfigItem In aConfig |
| 'Start a fresh dockstate |
| dsWorking = New DockState |
| 'Parse the string back into dock settings |
| dsWorking = DockState.Deserialize(strConfigItem) |
| 'Add the settings back into the current session |
| _currentDockStates.Add(dsWorking) |
| Next |
| Catch ex As Exception |
| 'Something was wrong with the data |
| 'Default back to blank so the page won't crash |
| End Try |
| 'Set the new value into the session variable |
| Session("UserPreferences.PortalSession") = _currentDockStates |
| Else |
| 'No config stored; use the default, speficied below |
| 'Quotes changed to apostrophes for string-friendly input |
| Dim strDefaultConfig = "[DEFAULT DOCK CONFIGURATION STRING HERE...]" |
| UpdateUserPreference("PortalConfiguration", Replace(strDefaultConfig, "'", """")) |
| Try |
| 'Now, use the newly saved default config to generate the docks |
| 'The UpdateUserPreference routine would have already stored it in a session |
| 'Convert the stored config to an array, splitting at the *s |
| Dim aConfig As Array = Split(Session("UserPreferences.PortalConfiguration"), "*") |
| Dim strConfigItem As String |
| Dim dsWorking As DockState |
| 'Parse through the array, turning the dockstate strings into dockstates |
| 'Then add the dockstates to the dockstate list |
| For Each strConfigItem In aConfig |
| 'Start a fresh dockstate |
| dsWorking = New DockState |
| 'Parse the string back into dock settings |
| dsWorking = DockState.Deserialize(strConfigItem) |
| 'Add the settings back into the current session |
| _currentDockStates.Add(dsWorking) |
| Next |
| Catch ex As Exception |
| 'Something was wrong with the data |
| 'Default back to blank so the page won't crash |
| End Try |
| 'Set the new value into the session variable |
| Session("UserPreferences.PortalSession") = _currentDockStates |
| End If |
| End If |
| Return _currentDockStates |
| End Get |
| Set(ByVal value As List(Of DockState)) |
| Session("UserPreferences.PortalSession") = value |
| 'Session being updated; Update the database too |
| 'Convert list of dockStates to a delimited string |
| 'We'll use * since commas are used in the dockStates |
| Dim sbListConverter As New System.Text.StringBuilder |
| For Each dockState As DockState In value |
| sbListConverter.AppendFormat("{0}*", dockState.ToString) |
| Next |
| Dim strDockConfig As String = sbListConverter.ToString.TrimEnd(Convert.ToChar("*")) |
| 'Save string to database |
| UpdateUserPreference("PortalConfiguration", strDockConfig) |
| End Set |
| End Property |
| Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) |
| If Not IsPostBack Then |
| 'Add the dock CSS files to the master page |
| Dim newStyleSheet As New HtmlLink() |
| newStyleSheet.Href = "skins/LightGreen/Dock.LightGreen.css" |
| newStyleSheet.Attributes.Add("type", "text/css") |
| newStyleSheet.Attributes.Add("rel", "stylesheet") |
| Page.Header.Controls.Add(newStyleSheet) |
| End If 'Not Postback |
| End Sub |
| Public Function GetZones() As ArrayList |
| Dim zones As New ArrayList() |
| zones.Add(zoneLeft) |
| zones.Add(zoneRight) |
| Return zones |
| End Function |
| Protected Sub Page_Init(ByVal sender As Object, ByVal e As EventArgs) |
| Dim i As Integer = 0 |
| While i < CurrentDockStates.Count |
| If CurrentDockStates(i).Closed = False Then |
| Dim dock As RadDock = CreateRadDockFromState(CurrentDockStates(i)) |
| RadDockLayout1.Controls.Add(dock) |
| CreateSaveStateTrigger(dock) |
| LoadWidget(dock) |
| End If |
| System.Math.Max(System.Threading.Interlocked.Increment(i), i - 1) |
| End While |
| End Sub |
| Protected Sub RadDockLayout1_LoadDockLayout(ByVal sender As Object, ByVal e As DockLayoutEventArgs) |
| For Each state As DockState In CurrentDockStates |
| e.Positions(state.UniqueName) = state.DockZoneID |
| e.Indices(state.UniqueName) = state.Index |
| Next |
| End Sub |
| Protected Sub RadDockLayout1_SaveDockLayout(ByVal sender As Object, ByVal e As DockLayoutEventArgs) |
| CurrentDockStates = RadDockLayout1.GetRegisteredDocksState() |
| End Sub |
| Private Function CreateRadDockFromState(ByVal state As DockState) As RadDock |
| Dim dock As New RadDock() |
| dock.ID = String.Format("RadDock{0}", state.UniqueName) |
| dock.ApplyState(state) |
| AddHandler dock.Command, AddressOf dock_Command |
| dock.Commands.Add(New DockCloseCommand()) |
| dock.Commands.Add(New DockExpandCollapseCommand()) |
| dock.EnableEmbeddedSkins = False |
| dock.Skin = "LightGreen" |
| Return dock |
| End Function |
| Private Function CreateRadDock() As RadDock |
| Dim docksCount As Integer = CurrentDockStates.Count |
| Dim dock As New RadDock() |
| dock.UniqueName = Guid.NewGuid().ToString() |
| dock.ID = String.Format("RadDock{0}", dock.UniqueName) |
| dock.Title = "" |
| dock.Text = "" |
| dock.Commands.Add(New DockCloseCommand()) |
| dock.Commands.Add(New DockExpandCollapseCommand()) |
| dock.EnableEmbeddedSkins = False |
| AddHandler dock.Command, AddressOf dock_Command |
| Return dock |
| End Function |
| Sub dock_Command(ByVal sender As Object, ByVal e As DockCommandEventArgs) |
| If e.Command.Name = "Close" Then |
| ScriptManager.RegisterStartupScript(UpdatePanel1, Me.[GetType](), "RemoveDock", String.Format("function _removeDock() {{" & Chr(13) & "" & Chr(10) & "" & Chr(9) & "Sys.Application.remove_load(_removeDock);" & Chr(13) & "" & Chr(10) & "" & Chr(9) & "$find('{0}').undock();" & Chr(13) & "" & Chr(10) & "" & Chr(9) & "$get('{1}').appendChild($get('{0}'));" & Chr(13) & "" & Chr(10) & "" & Chr(9) & "$find('{0}').doPostBack('DockPositionChanged');" & Chr(13) & "" & Chr(10) & "}};" & Chr(13) & "" & Chr(10) & "Sys.Application.add_load(_removeDock);", (DirectCast(sender, RadDock)).ClientID, UpdatePanel1.ClientID), True) |
| End If |
| End Sub |
| Private Sub CreateSaveStateTrigger(ByVal dock As RadDock) |
| dock.AutoPostBack = True |
| dock.CommandsAutoPostBack = True |
| Dim saveStateTrigger As New AsyncPostBackTrigger() |
| saveStateTrigger.ControlID = dock.ID |
| saveStateTrigger.EventName = "DockPositionChanged" |
| UpdatePanel1.Triggers.Add(saveStateTrigger) |
| saveStateTrigger = New AsyncPostBackTrigger() |
| saveStateTrigger.ControlID = dock.ID |
| saveStateTrigger.EventName = "Command" |
| UpdatePanel1.Triggers.Add(saveStateTrigger) |
| End Sub |
| Private Sub LoadWidget(ByVal dock As RadDock) |
| If String.IsNullOrEmpty(dock.Tag) Then |
| Return |
| End If |
| Dim widget As Control = LoadControl(dock.Tag) |
| dock.ContentContainer.Controls.Add(widget) |
| End Sub |
| Protected Sub ButtonAddDock_Click(ByVal sender As Object, ByVal e As EventArgs) |
| Dim dock As RadDock = CreateRadDock() |
| UpdatePanel1.ContentTemplateContainer.Controls.Add(dock) |
| ScriptManager.RegisterStartupScript(dock, Me.[GetType](), "AddDock", String.Format("function _addDock() {{" & Chr(13) & "" & Chr(10) & "" & Chr(9) & "Sys.Application.remove_load(_addDock);" & Chr(13) & "" & Chr(10) & "" & Chr(9) & "$find('{1}').dock($find('{0}'));" & Chr(13) & "" & Chr(10) & "" & Chr(9) & "$find('{0}').doPostBack('DockPositionChanged');" & Chr(13) & "" & Chr(10) & "}};" & Chr(13) & "" & Chr(10) & "Sys.Application.add_load(_addDock);", dock.ClientID, DropDownZone.SelectedValue), True) |
| CreateSaveStateTrigger(dock) |
| dock.Title = DroptDownWidget.SelectedItem.Text |
| dock.Tag = DroptDownWidget.SelectedValue |
| 'Style the dock, based upon its content |
| dock.Skin = "LightGreen" |
| LoadWidget(dock) |
| End Sub |
| End Class |
| End Namespace |