This is a migrated thread and some comments may be shown as answers.

CustomCommand only fired once

4 Answers 59 Views
Dock
This is a migrated thread and some comments may be shown as answers.
Christophe
Top achievements
Rank 1
Christophe asked on 20 Jun 2012, 06:35 AM
Hi,

I'm trying to create dynamic dock controls with customs command in their title bar. I've read everywhere that those dock must be re-created in the OnInit event which I think I'm doing.
Here's my code:
1 - I'm adding a dock to the DockLayout by clicking on a radbutton (RadButtonCreate_Click) and load a control within that dock via Loadcontrol.
Everything looks fine at that stage.

2 - When I click on my custom command "SaveToDB", it does work the way I like and insert all the data to the DB and update the title of my dock via a Dock Title Template implementing ITemplate.

3 - When I click again on that command "SaveToDB", nothing happens. The OnClientCommand is fired but the server side handler is no longer called.

What am I doing wrong here ? 

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["CurrentDockStatesDynamicDocks"];
        if (Object.Equals(_currentDockStates, null))
        {
            _currentDockStates = new List<DockState>();
            Session["CurrentDockStatesDynamicDocks"] = _currentDockStates;
        }
        return _currentDockStates;
    }
    set
    {
        Session["CurrentDockStatesDynamicDocks"] = value;
    }
}
 
private RadDock CreateRadDockFromState(DockState state)
{
    RadDock dock = new RadDock();
    try
    {
        dock.ID = string.Format("RadDock{0}", state.UniqueName);
 
        dock.ApplyState(state);
        dock.EnableRoundedCorners = true;
 
        dock.Command += new DockCommandEventHandler(dock_Command);
        dock.Commands.Add(new DockCloseCommand());
        dock.Commands.Add(new DockExpandCollapseCommand());
 
        var dockSaveCmd = new DockCommand();
        dockSaveCmd.Name = "SaveToDB";
        dockSaveCmd.Text = "Save";
        dockSaveCmd.CssClass = "sdSaveCmd";
        dockSaveCmd.OnClientCommand = "SaveStopToDB";
        dock.Commands.Add(dockSaveCmd);
    }
    catch (Exception ex)
    {
        return null;
        throw new Exception(ex.Message, ex.InnerException);
    }
    return dock;
}
 
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++)
    {
        RadDock dock = CreateRadDockFromState(CurrentDockStates[i]);
        RadDockLayout1.Controls.Add(dock);
        CreateSaveStateTrigger(dock);
    }
}
 
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;
 
    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);
}
 
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);
 
    }
    else if (e.Command.Name == "SaveToDB")
    {
        var dock = ((RadDock)sender);
        var stop = new Stop()
        {
            Id = int.Parse(dock.Tag),
            Name = ((RadTextBox)stopCtrl.FindControl("rtbName")).Text,
            Description = ((RadTextBox)stopCtrl.FindControl("TB_description")).Text,
        };
 
        if (stop.Id < 0)
        {
            stop.Id = stop.Insert();
            dock.Tag = stop.Id.ToString();
        }
        else
            stop.Update();
    }
}
 
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 page Session. This will enable us
    // to recreate the dock in the next Page_Init.
    CurrentDockStates = RadDockLayout1.GetRegisteredDocksState();
}
 
protected void RadButtonCreate_Click(object sender, EventArgs e)
{
    var dock = new RadDock();
    dock.DockMode = DockMode.Docked;
    dock.EnableRoundedCorners = true;
    dock.UniqueName = Guid.NewGuid().ToString();
    dock.ID = string.Format("RadDock{0}", dock.UniqueName);
    dock.Tag = "-1";
    StopFormTplEmpty widget = (StopFormTplEmpty)GlobalUtils.LoadControl(this, "~/Templates/StopFormTplEmpty.ascx");
    widget.EnableViewState = true;
    dock.ContentContainer.Controls.Add(widget);
 
    dock.TitlebarTemplate = new DockTitleTemplate(dock, StopType.Unknown, "New");
    dock.Width = Unit.Percentage(100);
    dock.Height = Unit.Pixel(420);
    dock.Commands.Add(new DockCloseCommand());
    dock.Commands.Add(new DockExpandCollapseCommand());
    var dockSaveCmd = new DockCommand();
    dockSaveCmd.Name = "SaveToDB";
    dockSaveCmd.Text = "Save";
    dockSaveCmd.CssClass = "sdSaveCmd";
    dockSaveCmd.OnClientCommand = "SaveStopToDB";
    dock.Commands.Add(dockSaveCmd);
    dock.CommandsAutoPostBack = true;
    dock.Command += new DockCommandEventHandler(dock_Command);
    UpdatePanel1.ContentTemplateContainer.Controls.Add(dock);
 
    ScriptManager.RegisterStartupScript(
    dock,
    this.GetType(),
    "AddDock",
    string.Format(@"function _addDock() {{ 
                        Sys.Application.remove_load(_addDock); 
                        $find('{1}').dock($find('{0}'),{2});  
                        $find('{0}').doPostBack('DockPositionChanged'); 
                        }}; 
                        Sys.Application.add_load(_addDock);", dock.ClientID, RadDockZoneStops.ID, 0),
                                                            true);
    CreateSaveStateTrigger(dock);
}

4 Answers, 1 is accepted

Sort by
0
Accepted
Slav
Telerik team
answered on 22 Jun 2012, 11:17 AM
Hello Chris,

The problem appears to be caused by incorrect registering of the dynamically added RadDock in the RadDockLayout. When the dock control is created and inserted on the page for the firs time, you should add it to the Controls collection of RadDockLayout.

You can find attached a sample page that uses your code and demonstrates the solution. There are a few additional changes that will improve the implementation of your scenario and are marked in the example. Please use it as a reference for your further development.

Kind regards,
Slav
the Telerik team
If you want to get updates on new releases, tips and tricks and sneak peeks at our product labs directly from the developers working on the RadControls for ASP.NET AJAX, subscribe to their blog feed now.
0
Christophe
Top achievements
Rank 1
answered on 02 Jul 2012, 01:23 AM
Hi Slav,

Thanks a lot for you help. It works nearly perfectly now. The CustomCommand event is fired when required, but now I have another issue.
Within each Dock, I'm loading a *.ascx via the LoadControl method. This control is consisting in a simple form with comboboxes, textboxes etc... Since these forms are containing data from a DB, I need to reload them in my "CreateRadDockFromState" function based on some unique DB index, and add the ascx to the "dock.ContentContainer.Controls" collection.

My issue is then, when I click on my Save custom command to update my form values into my DB, it first creates a postback event that will reload my docks via  "CreateRadDockFromState" and get the previous/old data from my DB and only then, calls my handler that is supposed to make the DB update. Therefore, it overwrites all changes I've made in my form with its DB values and then updates the DB with the exact same values. I end up in not being able to update anything from this form.

Is there anything I'm not doing or doing wrong ? 

I've started to have a look at the RadAjaxManager and the RadAjaxManagerProxy to see if that would be a better solution. What do you think ?

Thanks
0
Christophe
Top achievements
Rank 1
answered on 02 Jul 2012, 02:17 AM
Hi Slav,

News from my debbug investigation. I think there must be an "issue" with an event propagation due to the ASyncPostBackTrigger set up in the CreateSaveStateTrigger method:

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);

I think when I click on any command of my dock bar title, it triggers both "DockPositionChanged" and "Command" events, even though the position didn't changed at all.
Therefore it calls back my "CreateRadDockFromState" twice instead of just once. Any idea on how to fix this ? Am I missing something here ?

Thanks
0
Slav
Telerik team
answered on 04 Jul 2012, 08:50 AM
Hi Chris,

The ViewState of the dynamically created RadDock's content is not persisted, which leads to the examined behavior. To get the value, entered in a text box control, you can retrieve its UniqueID and use it with the property Page.Request.Form as shown below:
void dock_Command(object sender, DockCommandEventArgs e)
{
    if (e.Command.Name == "SaveToDB")
    {
        var dock = ((RadDock)sender);
        Control userControl = dock.ContentContainer.FindControl(dock.Tag) as Control; // the user control in RadDock is referenced
        TextBox textBox = userControl.FindControl("Textbox1") as TextBox; // the text box in the user control is referenced
        Session["inputText"] = Page.Request.Form[textBox.UniqueID]; // the value of the text box is retrieved
    }
}

This approach is valid for text boxes in the content of the RadDock. If you have additional elements, please let us know so that we can suggest an alternative for achieving the desired functionality.

Regards,
Slav
the Telerik team
If you want to get updates on new releases, tips and tricks and sneak peeks at our product labs directly from the developers working on the RadControls for ASP.NET AJAX, subscribe to their blog feed now.
Tags
Dock
Asked by
Christophe
Top achievements
Rank 1
Answers by
Slav
Telerik team
Christophe
Top achievements
Rank 1
Share this question
or