As per the title, I have managed to save the raddocklayout state to a database and restore it sucessfully. However, it only seems to be saving/restoring all the dock's positions within a dockzone. i.e. it restores docks to the appropriate dockzones and to their places within the dockzones.
However, it does not seem to be restoring the collapse state of any dock. I got the code from various forum posts and the demo etc.
What am I doing wrong?
Thanks,
Steve
My save code:
JavaScriptSerializer serializer = new JavaScriptSerializer(); |
string serializedPositions = serializer.Serialize(e.Positions); |
string serializedIndices = serializer.Serialize(e.Indices); |
string serializedLayout = serializer.Serialize(new string[] { serializedPositions, serializedIndices }); |
// save it to a SQL Server database |
My restore code:
string layout = /* get the string from the database */; |
if (!string.IsNullOrEmpty(layout)) |
{ |
JavaScriptSerializer serializer = new JavaScriptSerializer(); |
string[] positionsAndIndices = serializer.Deserialize<string[]>(layout); |
e.Positions = serializer.Deserialize<Dictionary<string, string>>(positionsAndIndices[0]); |
e.Indices = serializer.Deserialize<Dictionary<string, int>>(positionsAndIndices[1]); |
} |
19 Answers, 1 is accepted
The problem comes from the fact that the Unit object cannot be serialized. This means that once the object has been serialized and then deserialized, the properties such as Top, Left, Width and Height etc. will loose their values.
Please note that this has nothing to do with Telerik components but with the .NET Framework and missing serialization.This is a shortcoming of the .Net Framework but it could be overcomed. For example you could use the JavaScriptSerializer class to serialize the state of the docks and write your own implementation of a custom JavaScriptConverter class. This custom class will take care of serialization/deserialization of Unit objects.
I created a simple example(SaveDockPositionInDB/DefaultVB.aspx ) which illustrates how to save the state for collapsed, docked, floating etc. RadDocks in DB. Please find it attached.
Sincerely yours,
Petio Petkov
the Telerik team
Instantly find answers to your questions on the new Telerik Support Portal.
Check out the tips for optimizing your support resource searches.
You load/Save script works like a charm. I was hopping that I could get some assistance modifying this to look to the database on first load.I have tried:
'===========================
Protected Sub Page_Init(ByVal sender As Object, ByVal e As EventArgs)
If Not IsPostBack Then
Dim serializer As New Script.Serialization.JavaScriptSerializer()
Dim sDockState As String = ""
Try
dbCon = New SqlClient.SqlConnection(System.Configuration.ConfigurationManager.AppSettings("CO9"))
Dim SiteControlsCMD As New SqlClient.SqlCommand("Select dockState From siteControls WHERE PageId = 1", dbCon)
dbCon.Open()
Dim SiteControls_Reader As SqlClient.SqlDataReader = SiteControlsCMD.ExecuteReader()
Do While SiteControls_Reader.Read()
sDockState = SiteControls_Reader("dockState")
Loop
Catch
End Try
Dim currentDockStates As String() = sDockState.Split("|"c)
For Each stringState As String In currentDockStates
If stringState.Trim() <> String.Empty Then
Dim state As DockState = serializer.Deserialize(Of DockState)(stringState)
Dim dock As RadDock = CreateRadDockFromState(state)
RadDockLayout1.Controls.Add(dock)
CreateSaveStateTrigger(dock)
End If
Next
Else
Dim i As Integer = 0
While i < CurrentDockStates.Count
Dim dock As RadDock = CreateRadDockFromState(CurrentDockStates(i))
RadDockLayout1.Controls.Add(dock)
CreateSaveStateTrigger(dock)
System.Math.Max(System.Threading.Interlocked.Increment(i), i - 1)
End While
End If
End Sub
'=====================================================
It seems to always look to the session bject first.
Any help would be appreciated.
Mike Conine
You should put this code in RadDockLayout1_LoadDockLayout handler and the state will be loaded from the db only the first time page loads, e.g.
Protected Sub RadDockLayout1_LoadDockLayout(ByVal sender As Object, ByVal e As Telerik.Web.UI.DockLayoutEventArgs) |
If Not Page.IsPostBack Then |
Dim dock As RadDock = Nothing |
Dim serializer As New JavaScriptSerializer() |
Dim converters As New List(Of JavaScriptConverter)() |
converters.Add(New UnitConverter()) |
serializer.RegisterConverters(converters) |
'Get saved state string from the database - set it to dockState variable for example |
Dim dockState As String = "" |
Try |
_conn.Open() |
Dim command As New SqlCommand("select State from States where id=1", _conn) |
dockState = command.ExecuteScalar().ToString() |
_conn.Close() |
Catch |
End Try |
Dim currentDockStates As String() = dockState.Split("|"c) |
For Each stringState As String In currentDockStates |
If stringState.Trim() <> String.Empty Then |
Dim state As DockState = serializer.Deserialize(Of DockState)(stringState) |
'e.Positions(state.UniqueName) = state.DockZoneID |
'e.Indices(state.UniqueName) = state.Index |
dock = DirectCast(RadDockLayout1.FindControl(state.UniqueName), RadDock) |
dock.ApplyState(state) |
dock.Index = state.Index |
End If |
Next |
End If |
End Sub |
Let us know if you have other questions.
Regards,
Petio Petkov
the Telerik team
Instantly find answers to your questions on the new Telerik Support Portal.
Check out the tips for optimizing your support resource searches.
Thank you for the quick reply.
I keep running into issues configuring the following:
==============================================
Dim serializer As New Script.Serialization.JavaScriptSerializer()
Dim converters As New List(Of JavaScriptConverter)()
converters.Add(New UnitConverter())
serializer.RegisterConverters(converters)
==============================================
The break down seems to start with converters. I can set:
==============================================
Dim converters As New List(Of Script.Serialization.JavaScriptConverter)()
==============================================
When I do I get no options for converters.Add. The message i get is: Value of type 'System.Web.UI.WebControls.UnitConverter' cannot be converted to 'System.Web.Script.Serialization.JavaScriptConverter'.
When i run the app I get without converting I get:
==============================================
Type 'Telerik.Web.UI.DockState' is not supported for deserialization of an array.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: Type 'Telerik.Web.UI.DockState' is not supported for deserialization of an array.
==============================================Thank you for the assistance
Mike
Could you please open a new support thread and send us a running project where we could observe the mentioned errors? Once we receive it we will do our best to fix them for you.
Greetings,
Petio Petkov
the Telerik team
Instantly find answers to your questions on the new Telerik Support Portal.
Check out the tips for optimizing your support resource searches.
Thank you for the follow up. I altered my approach and I am simply iterating client side to grab the get_index() and then saving it as a Rank via an AJAX button click. Thus I do not know that i need to go with the requested solution.
However It may be an issue affecting others.
So i do not neccesarily need the fix but i would be more than happy to forward code if you wantt o check it out.
Mike
I'm glad to hear that you resolve the problem on your side.
If you still want to find what was wrong before, you can open a support thread and send us a running project where we could observe the problem on our side. Once we receive it we will do our best to resolve it and provide you a solution.
Let us know if you have any other questions.
Kind regards,
Petio Petkov
the Telerik team
Check out Telerik Trainer , the state of the art learning tool for Telerik products.
Using the code supplied, I run into the same issue as Mike originally did with the following line:
converters.Add(New UnitConverter()) |
Visual Studio returns error:
Error 70 Value of type 'System.Web.UI.WebControls.UnitConverter' cannot be converted to 'System.Web.Script.Serialization.JavaScriptConverter'. |
Any suggests?
My concern was not with open closed state. I ultimately wanted to save and retrieve the dock position and rank. I gave up on the recommendations and went a different direction.
I generate an update panel at run time based upon a database value. At the same time utilize a user control to do the heavy lifting. The User Control essentially becomes the dockZone. In the user control i have a textBox I pass the dock Id.
The code for loading the docks is:
'================================================================== |
'Build update panels. Update panels are in the sitetemplate tagged |
'by page id. they are concated as HWLeft,HWRight... The split is "," |
'================================================================== |
Dim updatePanels As String = AdminLogic.Get_TemplateData("updatePanels", PageId) |
Dim panelsArray() As String = updatePanels.Split(",") |
Dim i As Integer |
For i = 0 To UBound(panelsArray) 'run through the list of update panels |
_Location = panelsArray(i) |
Dim wPlaceHolder As PlaceHolder |
wPlaceHolder = Page.FindControl(_Location) |
Try |
Dim genericControl As UserControl = LoadControl("~/UCL/GenericEdit.ascx") |
Dim control_Label As Label = genericControl.FindControl("controlLabel") |
control_Label.Text = _Location |
wPlaceHolder.Controls.Add(genericControl) |
Catch |
End Try |
Next i |
When the RadDocks fill the dockZone I utilize another textBox to store the information.
when i drop the Dock I essentially delete the textBox value, iterate through the DockZone and repopulate the textbox
The code for saving is:
Protected Sub dockButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles dockButton.Click |
Dim zone As String = zoneLabel.Text |
Dim updateRank As New RadDockTableAdapters.SiteControlsTableAdapter() |
Dim i As Integer |
Dim dock As String = dockLabel.Text |
Dim dockArray() As String = dock.Split("|") |
For i = 0 To UBound(dockArray) - 1 |
'MsgBox(dockArray(i)) 'test alert |
Dim dockSplit() As String = dockArray(i).Split("^") |
updateRank.UpdateRank(dockSplit(1), zone, dockSplit(0)) |
Next i |
End Sub |
To get around the Ajax issue I utilize some hidden text fields.
As to your dilemma i assume that you could also incorporate the state open/closed. I know this is not ectremely elegant but it gets the job done :)
I am sure that I could tewak this to impliment session or application state. Potentially I could even take it directly to the database. i was satisfied that hidden textboxes fit the bill.
If you think this is a direction to go let me know and I can look more closely at what I did.
Mike
I ran the project that Petio provided (attached) in some of the previous posts of this thread, and everything works fine. No errors occurred and the state of the docks is saved and restored correctly. Also the collapse and closed state of every RadDock is preserved and respectively recreated on a postback.
This being said, my suggestion is to open a new support ticket and send us a sample running project where the described behavior can be observed. We need to have a clearer picture of your project in order to offer you an adequate solution.
Sincerely yours,
Pero
the Telerik team
Instantly find answers to your questions on the new Telerik Support Portal.
Check out the tips for optimizing your support resource searches.
Thanks.
How can I modify this to use a users login name for the ID.
I made a new database and made the id field text so I can store "CORP\brad.baker"
I need to modify this
Dim command As New SqlCommand("select State from States where id=1", _conn) so that insted of 1 its the user name.
I also need to modify this
Dim
command As New SqlCommand([String].Format("update States set State='{0}' where id=1", dockState), _conn)
so that insted of 1 it uses the user name but I also need to add a check becuase if its not in the DB to begin with it needs to insert and not update.
Imports System |
Imports System.Data |
Imports System.Configuration |
Imports System.Collections |
Imports System.Web |
Imports System.Web.Security |
Imports System.Web.UI |
Imports System.Web.UI.WebControls |
Imports System.Web.UI.WebControls.WebParts |
Imports System.Web.UI.HtmlControls |
Imports System.Data.SqlClient |
Imports Telerik.Web.UI |
Imports System.Collections.Generic |
Imports System.Text |
Imports System.Web.Script.Serialization |
Partial Public Class DefaultVB |
Inherits System.Web.UI.Page |
Private _conn As New SqlConnection(ConfigurationManager.ConnectionStrings("DockConnectionString").ConnectionString) |
Private _count As Integer = 0 |
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) |
End Sub |
Protected Sub RadDockLayout1_LoadDockLayout(ByVal sender As Object, ByVal e As Telerik.Web.UI.DockLayoutEventArgs) |
Dim dock As RadDock = Nothing |
Dim serializer As New JavaScriptSerializer() |
Dim converters As New List(Of JavaScriptConverter)() |
converters.Add(New UnitConverter()) |
serializer.RegisterConverters(converters) |
'Get saved state string from the database - set it to dockState variable for example |
Dim dockState As String = "" |
Try |
_conn.Open() |
Dim command As New SqlCommand("select state from states where userid='" + Context.User.Identity.Name + "'", _conn) |
dockState = command.ExecuteScalar().ToString() |
_conn.Close() |
Catch |
End Try |
Dim currentDockStates As String() = dockState.Split("|"c) |
For Each stringState As String In currentDockStates |
If stringState.Trim() <> String.Empty Then |
Dim state As DockState = serializer.Deserialize(Of DockState)(stringState) |
'e.Positions(state.UniqueName) = state.DockZoneID |
'e.Indices(state.UniqueName) = state.Index |
dock = DirectCast(RadDockLayout1.FindControl(state.UniqueName), RadDock) |
dock.ApplyState(state) |
End If |
Next |
End Sub |
Protected Sub RadDockLayout1_SaveDockLayout(ByVal sender As Object, ByVal e As Telerik.Web.UI.DockLayoutEventArgs) |
Dim dockState As String |
Dim serializer As New JavaScriptSerializer() |
Dim converters As New List(Of JavaScriptConverter)() |
converters.Add(New UnitConverter()) |
serializer.RegisterConverters(converters) |
Dim stateList As List(Of DockState) = RadDockLayout1.GetRegisteredDocksState() |
Dim serializedList As New StringBuilder() |
Dim i As Integer = 0 |
While i < stateList.Count |
serializedList.Append(serializer.Serialize(stateList(i))) |
serializedList.Append("|") |
System.Math.Max(System.Threading.Interlocked.Increment(i), i - 1) |
End While |
dockState = serializedList.ToString() |
Dim uniqid As Integer |
Try |
_conn.Open() |
Dim command As New SqlCommand("select uniqueid from states where userid='" + Context.User.Identity.Name + "'", _conn) |
uniqid = Val(command.ExecuteScalar().ToString()) |
_conn.Close() |
Catch |
End Try |
'_conn.Close() |
If dockState.Trim() <> [String].Empty Then |
If uniqid = 0 Then |
Try |
_conn.Open() |
' Dim command As New SqlCommand([String].Format("update States set State='{0}' where id=1", dockState), _conn) |
Dim command As New SqlCommand([String].Format("insert into states (userid, state) values('" + Context.User.Identity.Name + "','{0}')", dockState), _conn) |
' Dim command As New SqlCommand([String].Format("insert into dbo.states (uniqueid,userid, state) values('1','test','test')", dockState), _conn) |
command.ExecuteNonQuery() |
_conn.Close() |
Catch |
End Try |
Else |
MsgBox("Hi") |
Try |
_conn.Open() |
' Dim command As New SqlCommand([String].Format("update States set State='{0}' where id=1", dockState), _conn) |
Dim command As New SqlCommand([String].Format("update states set state ='{0}' where uniqueid='" + uniqid + "'", dockState), _conn) |
'Dim command As New SqlCommand([String].Format("insert into states (userid, state) values('test','test')", dockState), _conn) |
command.ExecuteNonQuery() |
_conn.Close() |
Catch |
End Try |
End If |
End If |
End Sub |
End Class |
It seems that the connection to the DataBase is not closed correctly when an exception is thrown. I got the same errors when trying to save the state in the DataBase. You should close the connection anytime you are opening a connection as shown in the code below:
Try |
_conn.Open() |
Dim command As New SqlCommand("select uniqueid from States where id='" + UserID + "'", _conn) |
uniqid = Val(command.ExecuteScalar().ToString()) |
Catch |
Finally |
_conn.Close() |
End Try |
Let us know if the problem still exists.
Greetings,
Pero
the Telerik team
Instantly find answers to your questions on the new Telerik Support Portal.
Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
Imports System |
Imports System.Data |
Imports System.Configuration |
Imports System.Collections |
Imports System.Web |
Imports System.Web.Security |
Imports System.Web.UI |
Imports System.Web.UI.WebControls |
Imports System.Web.UI.WebControls.WebParts |
Imports System.Web.UI.HtmlControls |
Imports System.Data.SqlClient |
Imports Telerik.Web.UI |
Imports System.Collections.Generic |
Imports System.Text |
Imports System.Web.Script.Serialization |
Partial Public Class DefaultVB |
Inherits System.Web.UI.Page |
Private _conn As New SqlConnection(ConfigurationManager.ConnectionStrings("DockConnectionString").ConnectionString) |
Private _count As Integer = 0 |
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) |
End Sub |
Protected Sub RadDockLayout1_LoadDockLayout(ByVal sender As Object, ByVal e As Telerik.Web.UI.DockLayoutEventArgs) |
Dim dock As RadDock = Nothing |
Dim serializer As New JavaScriptSerializer() |
Dim converters As New List(Of JavaScriptConverter)() |
converters.Add(New UnitConverter()) |
serializer.RegisterConverters(converters) |
'Get saved state string from the database - set it to dockState variable for example |
Dim dockState As String = "" |
Try |
_conn.Open() |
Dim command As New SqlCommand("select state from states where userid='" + Context.User.Identity.Name + "'", _conn) |
dockState = command.ExecuteScalar().ToString() |
Catch |
Finally |
_conn.Close() |
End Try |
Dim currentDockStates As String() = dockState.Split("|"c) |
For Each stringState As String In currentDockStates |
If stringState.Trim() <> String.Empty Then |
Dim state As DockState = serializer.Deserialize(Of DockState)(stringState) |
'e.Positions(state.UniqueName) = state.DockZoneID |
'e.Indices(state.UniqueName) = state.Index |
dock = DirectCast(RadDockLayout1.FindControl(state.UniqueName), RadDock) |
dock.ApplyState(state) |
End If |
Next |
End Sub |
Protected Sub RadDockLayout1_SaveDockLayout(ByVal sender As Object, ByVal e As Telerik.Web.UI.DockLayoutEventArgs) |
Dim dockState As String |
Dim serializer As New JavaScriptSerializer() |
Dim converters As New List(Of JavaScriptConverter)() |
converters.Add(New UnitConverter()) |
serializer.RegisterConverters(converters) |
Dim stateList As List(Of DockState) = RadDockLayout1.GetRegisteredDocksState() |
Dim serializedList As New StringBuilder() |
Dim i As Integer = 0 |
While i < stateList.Count |
serializedList.Append(serializer.Serialize(stateList(i))) |
serializedList.Append("|") |
System.Math.Max(System.Threading.Interlocked.Increment(i), i - 1) |
End While |
dockState = serializedList.ToString() |
Dim uniqid As Integer |
Try |
_conn.Open() |
Dim command As New SqlCommand("select uniqueid from states where userid='" + Context.User.Identity.Name + "'", _conn) |
uniqid = Val(command.ExecuteScalar().ToString()) |
Catch |
Finally |
_conn.Close() |
End Try |
If dockState.Trim() <> [String].Empty Then |
If uniqid = 0 Then |
Try |
_conn.Open() |
' Dim command As New SqlCommand([String].Format("update States set State='{0}' where id=1", dockState), _conn) |
Dim command As New SqlCommand([String].Format("insert into states (userid, state) values('" + Context.User.Identity.Name + "','{0}')", dockState), _conn) |
' Dim command As New SqlCommand([String].Format("insert into dbo.states (uniqueid,userid, state) values('1','test','test')", dockState), _conn) |
command.ExecuteNonQuery() |
Catch |
Finally |
_conn.Close() |
End Try |
Else |
MsgBox(uniqid) |
Try |
_conn.Open() |
' Dim command As New SqlCommand([String].Format("update States set State='{0}' where id=1", dockState), _conn) |
Dim command As New SqlCommand([String].Format("update states set state ='" + dockState + "' where uniqueid=" + uniqid + ""), _conn) |
'Dim command As New SqlCommand([String].Format("insert into states (userid, state) values('test','test')", dockState), _conn) |
command.ExecuteNonQuery() |
Catch |
Finally |
_conn.Close() |
End Try |
End If |
End If |
End Sub |
End Class |
For your convenience I have created a sample project that saves the state of the RadDocks based on which user is logged into the system. At the moment the Database that stores the states of the RadDocks does not contain any information, so basically when the user logs for the first time a row is inserted into the States table with the Id and the State of the RadDocks. The project is attached to the thread, you only need to paste the DLL's in the Bin folder. To run the application load the Login.aspx page first. After login you will be redirected to the page that contains the RadDocks.
Sincerely yours,
Pero
the Telerik team
Instantly find answers to your questions on the new Telerik Support Portal.
Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
The way to save dock layouts has obviously switched in this version (Q3 2010) and there are no breaking changes in the release notes. This is definitely a breaking change, i had to spend over an hour updating all of my code to this new way as the old way only produces errors after updating. Kind of frustrating. If you are going to update something that actually breaks previous code, you need to let us know.
Thanks.
This seems to be working as in the example, looks like it is loading up the "original" state in the session before the docklayouts are persisted from the cookie so that should work. My bad!
Thanks!