Code snippet below:
Protected Sub LoadDock(ByVal sender As Object, ByVal e As CommandEventArgs)
Dim id As String = e.CommandName
lblErr.Text = id.ToString
Dim ds As New DataSet
ds = odata.ReturnDS(
"sp_GadgetsByGadgetName", "@GadgetName", id.ToString)
If LoadedGadgets(ReturnUserName() & "_" & ds.Tables("Generic").Rows(0).Item("GN")) = "False" Then
'Create Dock
Dim dock As New RadDock()
Dim widget As New UserControl
widget = LoadControl(ds.Tables(
"Generic").Rows(0).Item("GadgetContent"))
Dim X As Integer = (ResolutionX / 2) - (CInt(ds.Tables("Generic").Rows(0).Item("GadgetWidth")) / 2)
Dim Y As Integer = (ResolutionY / 2) - (CInt(ds.Tables("Generic").Rows(0).Item("GadgetHeight")) / 2)
With dock
.ID = ReturnUserName() &
"_" & ds.Tables("Generic").Rows(0).Item("GN")
.Title = ds.Tables(
"Generic").Rows(0).Item("GN")
.Skin =
"WebBlue"
.UniqueName = Guid.NewGuid().ToString()
.Width =
CInt(ds.Tables("Generic").Rows(0).Item("GadgetWidth"))
.Height =
CInt(ds.Tables("Generic").Rows(0).Item("GadgetHeight"))
.Left = X
.Top = Y
.Resizable =
False
.Pinned =
False
.OnClientDragEnd =
"Moved"
.OnClientDragStart =
"OnClientDragStart"
.DockHandle = DockHandle.TitleBar
.DockMode = DockMode.Floating
.BorderStyle = BorderStyle.None
.Attributes.Add(
"style", "filter:progid:DXImageTransform.Microsoft.Shadow(direction=145, color=#4b4b4b, strength=5) progid:DXImageTransform.Microsoft.Alpha(opacity=95);")
.OnClientCommand =
"OnClientCommand"
.EnableViewState =
False
End With
RadDockLayout1.Controls.Add(dock)
dock.ContentContainer.Controls.Add(widget)
PlaceGadgetInternal(ds.Tables(
"Generic").Rows(0).Item("GN"), X.ToString, Y.ToString, ReturnUserName)
End If
ds.Clear()
ds.Dispose()
ds =
Nothing
End Sub
14 Answers, 1 is accepted
You could receive such an error if you create two RadDocks with equal ID's or update via AJAX a floating dock.
If you want to use Ajax with RadDock control all RadDocks should be docked and you should update all RadDockZones.
A simple example which illustrates how to use RadDock with RadAjax is available here:
http://demos.telerik.com/aspnet-ajax/dock/examples/myportal/defaultcs.aspx
I am updating the floating dock locations to a database whenever a new dock is added or a dock is moved. Docking to a zone however, is out of the question as these panels must remain floating. Is this a limitation of RadDock? I seem to remember seeing a post to that effect and that the Q12009 release was supposed to fix it?
You could use RadDock with ajax as is described below:
1) You can update RadDockZones while all RadDocks are docked.
2) You can update only the RadDock's content via AJAX, e.g. Add the entire content in UpdatePanel and add the UpdatePanel in the RadDock
Hope this helps.
I have no RadDockZones on the page, so that is not an option. Also, I cannot simply update the dock's content as I must also inquire about it's floating location as well.
Basically, this is the flow of events:
There is a stage or desktop that houses the floating docks. A user can add a particular dock to that stage by adding it from a menu. When they add a new floating dock to the stage it refreshes the two update panels (1 for the menu- to remove the added dock from the menu, and 1 for the stage where the new floating dock appears). When a user moves a floating dock on the stage it updates the stage's update panel to save the position for the user's next visit.
ASPX:
<%@ register tagprefix="telerik" namespace="Telerik.Web.UI" assembly="Telerik.Web.UI" %> |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/tr/xhtml11/dtd/xhtml11.dtd"> |
<html xmlns="http://www.w3.org/1999/xhtml"> |
<head runat="server"> |
<!--[if lte IE 6]> |
<style type="text/css"> |
.raddockzone{height:200px} |
</style> |
<![endif]--> |
</head> |
<body class="BODY"> |
<form id="Form1" method="post" runat="server"> |
<asp:scriptmanager id="ScriptManager" runat="server" /> |
<div class="module"> |
Select Module: |
<asp:dropdownlist runat="server" id="DroptDownWidget" width="150"> |
<asp:listitem text="ExchangeRates.ascx" value="Controls/ExchangeRates.ascx" selected="true"></asp:listitem> |
<asp:listitem text="Horoscopes.ascx" value="Controls/Horoscopes.ascx"></asp:listitem> |
<asp:listitem text="News.ascx" value="Controls/News.ascx"></asp:listitem> |
<asp:listitem text="Weather.ascx" value="Controls/Weather.ascx"></asp:listitem> |
</asp:dropdownlist> |
<br/>Select Docking Zone: |
<asp:dropdownlist id="DropDownZone" runat="server" datasource="<%#GetZones() %>" |
datatextfield="ID" datavaluefield="ClientID" width="150"> |
</asp:dropdownlist> |
<asp:button runat="server" id="ButtonAddDock" text="Add Dock" onclick="ButtonAddDock_Click" /> |
</div> |
<br/> |
<telerik:raddocklayout runat="server" id="RadDockLayout1" |
onsavedocklayout="RadDockLayout1_SaveDockLayout" |
onloaddocklayout="RadDockLayout1_LoadDockLayout"> |
<table> |
<tr> |
<td> |
<telerik:raddockzone runat="server" id="RadDockZone1" width="300" |
FitDocks="true" Height="400" > |
</telerik:raddockzone> |
</td> |
<td> |
<telerik:raddockzone runat="server" id="RadDockZone2" width="300" |
FitDocks="true" Height="400" > |
</telerik:raddockzone> |
</td> |
</tr> |
</table> |
<div style="display:none"> |
Hidden UpdatePanel, which is used to receive the new dock controls. |
We will move them with script to the desired initial dock zone. |
<asp:updatepanel runat="server" id="UpdatePanel1"> |
<triggers> |
<asp:asyncpostbacktrigger controlid="ButtonAddDock" eventname="Click" /> |
</triggers> |
</asp:updatepanel> |
</div> |
</telerik:raddocklayout> |
</form> |
</body> |
</html> |
public partial class DefaultCS : System.Web.UI.Page |
{ |
private List<DockState> CurrentDockStates |
{ |
get |
{ |
//Store the info about the added docks in the session. For real life |
// applications we recommend using database or other storage medium |
// for persisting this information. |
List<DockState> _currentDockStates = (List<DockState>)Session["CurrentDockStatesMyPortal"]; |
if (Object.Equals(_currentDockStates, null)) |
{ |
_currentDockStates = new List<DockState>(); |
Session["CurrentDockStatesMyPortal"] = _currentDockStates; |
} |
return _currentDockStates; |
} |
set |
{ |
Session["CurrentDockStatesMyPortal"] = value; |
} |
} |
protected void Page_Load(object sender, EventArgs e) |
{ |
if (!IsPostBack) |
{ |
DropDownZone.DataBind(); |
DropDownZone.Items.Add("AddItToThePage"); |
} |
} |
public ArrayList GetZones() |
{ |
ArrayList zones = new ArrayList(); |
zones.Add(RadDockZone1); |
zones.Add(RadDockZone2); |
return zones; |
} |
protected void Page_Init(object sender, EventArgs e) |
{ |
//Recreate the docks in order to ensure their proper operation |
for (int i = 0; i < CurrentDockStates.Count; i++) |
{ |
if (CurrentDockStates[i].Closed == false) |
{ |
RadDock dock = CreateRadDockFromState(CurrentDockStates[i]); |
//We will just add the RadDock control to the RadDockLayout. |
// You could use any other control for that purpose, just ensure |
// that it is inside the RadDockLayout control. |
// The RadDockLayout control will automatically move the RadDock |
// controls to their corresponding zone in the LoadDockLayout |
// event (see below). |
RadDockLayout1.Controls.Add(dock); |
//We want to save the dock state every time a dock is moved. |
CreateSaveStateTrigger(dock); |
//Load the selected widget |
LoadWidget(dock); |
} |
} |
} |
protected void RadDockLayout1_LoadDockLayout(object sender, DockLayoutEventArgs e) |
{ |
//Populate the event args with the state information. The RadDockLayout control |
// will automatically move the docks according that information. |
foreach (DockState state in CurrentDockStates) |
{ |
e.Positions[state.UniqueName] = state.DockZoneID; |
e.Indices[state.UniqueName] = state.Index; |
} |
} |
protected void RadDockLayout1_SaveDockLayout(object sender, DockLayoutEventArgs e) |
{ |
//Save the dock state in the session. This will enable us |
// to recreate the dock in the next Page_Init. |
CurrentDockStates = RadDockLayout1.GetRegisteredDocksState(); |
} |
private RadDock CreateRadDockFromState(DockState state) |
{ |
RadDock dock = new RadDock(); |
dock.ID = string.Format("RadDock{0}", state.UniqueName); |
dock.Width = Unit.Pixel(300); |
dock.Height = Unit.Pixel(300); |
dock.ApplyState(state); |
dock.Command += new DockCommandEventHandler(dock_Command); |
dock.Commands.Add(new DockCloseCommand()); |
dock.Commands.Add(new DockExpandCollapseCommand()); |
return dock; |
} |
private RadDock CreateRadDock() |
{ |
int docksCount = CurrentDockStates.Count; |
RadDock dock = new RadDock(); |
dock.UniqueName = Guid.NewGuid().ToString(); |
dock.ID = string.Format("RadDock{0}", dock.UniqueName); |
dock.Title = "Dock"; |
dock.Text = string.Format("Added at {0}", DateTime.Now); |
dock.Width = Unit.Pixel(300); |
dock.Height = Unit.Pixel(300); |
dock.Style.Add("zIndex", "0"); |
dock.Commands.Add(new DockCloseCommand()); |
dock.Commands.Add(new DockExpandCollapseCommand()); |
dock.Command += new DockCommandEventHandler(dock_Command); |
return dock; |
} |
void dock_Command(object sender, DockCommandEventArgs e) |
{ |
if (e.Command.Name == "Close") |
{ |
ScriptManager.RegisterStartupScript( |
UpdatePanel1, |
this.GetType(), |
"RemoveDock", |
string.Format(@"function _removeDock() {{ |
Sys.Application.remove_load(_removeDock); |
$find('{0}').undock(); |
$get('{1}').appendChild($get('{0}')); |
$find('{0}').doPostBack('DockPositionChanged'); |
}}; |
Sys.Application.add_load(_removeDock);", ((RadDock)sender).ClientID, UpdatePanel1.ClientID), |
true); |
} |
} |
private void CreateSaveStateTrigger(RadDock dock) |
{ |
//Ensure that the RadDock control will initiate postback |
// when its position changes on the client or any of the commands is clicked. |
//Using the trigger we will "ajaxify" that postback. |
dock.AutoPostBack = true; |
dock.CommandsAutoPostBack = true; |
dock.Style.Add("zIndex", "0"); |
AsyncPostBackTrigger saveStateTrigger = 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); |
} |
private void LoadWidget(RadDock dock) |
{ |
if (string.IsNullOrEmpty(dock.Tag)) |
{ |
return; |
} |
Control widget = LoadControl(dock.Tag); |
dock.ContentContainer.Controls.Add(widget); |
} |
protected void ButtonAddDock_Click(object sender, EventArgs e) |
{ |
RadDock dock = CreateRadDock(); |
//In order to optimize the execution speed we are adding the dock to a |
// hidden update panel and then register a script which will move it |
// to RadDockZone1 after the AJAX request completes. If you want to |
// dock the control in other zone, modify the script according your needs. |
UpdatePanel1.ContentTemplateContainer.Controls.Add(dock); |
if (DropDownZone.SelectedValue != "AddItToThePage") |
{ |
ScriptManager.RegisterStartupScript( |
dock, |
this.GetType(), |
"AddDock", |
string.Format(@"function _addDock() {{ |
Sys.Application.remove_load(_addDock); |
$find('{0}').originalZIndex = ''; |
$find('{1}').dock($find('{0}')); |
$find('{0}').doPostBack('DockPositionChanged'); |
}}; |
Sys.Application.add_load(_addDock);", dock.ClientID, DropDownZone.SelectedValue), |
true); |
} |
else |
{ |
//Add RadDock to the form/not in zone. |
ScriptManager.RegisterStartupScript( |
dock, |
this.GetType(), |
"AddDockToPage", |
string.Format(@"function _addDockToPage() {{ |
Sys.Application.remove_load(_addDockToPage); |
var dock = $find('{0}'); |
dock._form.appendChild(dock.get_element()); |
dock.set_closed(false); |
dock.set_left(100); |
dock.set_top(100); |
$find('{0}').doPostBack('DockPositionChanged'); |
}}; |
Sys.Application.add_load(_addDockToPage);", dock.ClientID), |
true); |
} |
//Right now the RadDock control is not docked. When we try to save its state |
// later, the DockZoneID will be empty. To workaround this problem we will |
// set the AutoPostBack property of the RadDock control to true and will |
// attach an AsyncPostBackTrigger for the DockPositionChanged client-side |
// event. This will initiate second AJAX request in order to save the state |
// AFTER the dock was docked in RadDockZone1. |
CreateSaveStateTrigger(dock); |
//Load the selected widget in the RadDock control |
dock.Tag = DroptDownWidget.SelectedValue; |
LoadWidget(dock); |
} |
} |
Hope this helps.
Thanks. Do you know if this code example will still work if I'm saving and getting the positions of the docks with a database instead of the session method you provided?
Thanks,
Kurt
And save the current state in a DB in the RadDockLayout1_SaveDockLayout handler.
Thanks, you're a true Jedi Master! I'll try it out and let you know.
Best Regards,
Kurt
I adapt your example to open docks only in floatable mode (basically removing the raddockzone related code). I create an asp site and all is working good.
Now I have to integrate my solution into a sharepoint 2010 web part. The problem I'm facing now is that the script that is executed in client side (AddDockToPage) at the first ajax call is giving an error.
The line var dock = $find('{0}'); is returning null. The HTML generated by the dock is present on the page but it seems that the corresponding raddock javascript instance is not.
Any idea?
One problem for the issue might be because you are ajaxifying floating docks. Here is detailed description on why there might be a problem:
Note that, when ajaxifying floating docks, once a dock is moved it goes outside of the UpdatePanel. This initiates new ajax request, and the UpdatePanel refreshes its content. However, since we have dragged the dock outside of the UpdatePanel, an identical dock will be created on its place in the UpdatePanel, and this will result in a JavaScript error. This JS error causes the dock to not be created correctly on the client, and that's why the $find shortcut returns null.
This being said, please make sure the docks are within the update panel when doing ajax calls.
Another thing that might be causing the issue is, the fact that incorrect ID is passed to the $find method. Could you please compare the parameter passed to the method, and the id attribute of the dock's outermost HTML element? If they are different then this is the problem for sure.
Of none of the above helps, please open a new support ticket and send us a sample demo that shows the problem.
Regards,
Pero
the Telerik team
Thanks for the answer.
I understand the fact that when moved, the dock is placed outside the update panel but my problem occurs at the very first ajax request (no docks exists in the page at this point). This request adds a new Dock to the hidden update panel in server side and then the javascript code is executed at client side after the call is done. This code should move the dock to the page.
var dock = $find('{0}'); |
dock._form.appendChild(dock.get_element()); |
At this point the $find function returns null on client side. I pass the correct Id to this function as it appears in the dock's Html element.
Other thing I realized is if I make a full postback, the $find function seems to start working.
I managed to make my solution work in simple asp site but when moving to sharepoint the problem occurs.
Could it be a sharepoint 2010 issue or conflict? I already tried the hidden update panel approach and also using the radAjaxManager but the same problem occurs at the first ajax request. It looks like to me that the RadDock client instance is not created when added via Ajax.
Michael Pinheiro
Thank you for opening the support ticket. I provided the solution there, but I will also post it here so it is available to our community. Here it is:
I examined your code, and noticed that the script registered from the server is causing the problem. The script added with the AjaxManager will be immediately executed when the HTML comes to the client, even before the Ajax controls are created on the client. That's why the $find method returns null, the dock's client object is not created yet.
To fix this issue, you should change the script a little bit, so it is executed after all controls are created, like Application.load for example. Here is how the script should look like:
string
script =
string
.Format(@"
function _addDock()
{{
var dock = $find(
'{0}'
);
alert(
'$find() returning value: '
+ dock);
dock._form.appendChild(dock.get_element());
Sys.Application.remove_load(_addDock);
}}
Sys.Application.add_load(_addDock);
", dock.ClientID);
AjaxManager.ResponseScripts.Add(script);
All the best,
Pero
the Telerik team