Ajaxifying dynamically created docks.

4 posts, 1 answers
  1. Sean
    Sean avatar
    200 posts
    Member since:
    Nov 2010

    Posted 05 Jul 2011 Link to this post

    Hi all,

    I am looking to achieve the following functionality: All events whose effects are self-contained to a RadDock should only cause post-back for that specific RadDock.

    That being said, it is (slightly!) more complicated than this. All my RadDocks and RadDockZones on my page are dynamically created and regenerated.

    I have reviewed the information given here, but I did not find this documentation enough to successfully achieve my goal. As such, I have a few questions.

    • I understand that there is an inherited complexity to this issue in the fact that RadDocks are able to be moved between RadDockZones. This appears to disqualify making the RadDock the designated 'control initiating post-back.' If I attempt to say "RadAjaxManager1.AjaxSettings.Add(dock, dock, null)" I am told that RadDockZone must have RadDock as child (and not this hidden update panel). As such, it is my belief that I will be achieving my desired results through wrapping of the RadDockZone in a hidden update panel, and not each individual RadDock.
    • That being said, my project does have constraints which may be useful/relevant to this issue -- Each RadDockZone has a 0 to 1 relationship with a RadDock. That is, RadDockZones with greater than 1 RadDock is not a supported scenario for my project. In addition, each RadPane on my page will have no more than 1 RadDockZone on it. Keeping things very simple 1:1:1 display.
    • In addition, each of my RadDocks is currently housing an UpdatePanel. This is used to update the contents of the dock instantly (charts that drill-down.) I know that UpdatePanels may sometimes cause conflicts, so I thought this was worth mentioning.
    • The RadAjaxManager documentation states that adding AJAX pairs dynamically to the RadAjaxManager should only be performed during Page_Load. I am curious if I need to perform initial "hook-up" of the setting when the control is dynamically created and then regenerate this state similarly to how all the other states on my page are regenerated. An example:

    protected void LstBxSettings_Dropped(object sender, RadListBoxDroppedEventArgs e)
    {
        RadDockZone dockZone = DashboardLayoutManager.Instance.RegisteredDockZones.FirstOrDefault(registeredDockZone => e.HtmlElementID.Contains(registeredDockZone.ID));
     
        if (!object.Equals(dockZone, null) && !dockZone.Docks.Any())
        {
            RadPane activeControlPane = (RadPane)dockZone.Parent;
            Orientation orientation = (Orientation)Enum.Parse(typeof(Orientation), e.SourceDragItems[0].Value);
            CormantRadSplitter newContent = CreationManager.CreateNewContent(orientation, activeControlPane);
            //Put newly created control in front so it will always be visible. (E.G. RadDockZone1 fights with it)
            activeControlPane.Controls.AddAt(0, newContent);
            RadControlManager.SaveNewContent(newContent);
            lstBxSettings.ClearSelection();
        }
    }

    This is a piece of code which is responsible for creating a new RadDock on my page, as well as attaching it to a RadDockZone. Note that RadDockLayout is not used (I've implemented my own). I am wondering if I need to say "RadAjaxManager1.AjaxSettings.AddAjaxSetting(dockZone, dock, null)" here during creation of this control. My gut is saying, "Yes. You do" because the controls are rendered to the user immediately after creation. If I only hook up settings during Page_Load then the control will be displayed to the user once, then a post back occurs, page_load fires, and now the control is wrapped in an update panel. As such, it is my belief that it is necessary to add it to AjaxManager immediately. Please correct me if I am wrong here.

    Now, lets talk about what needs to occur every time a page load occurs. RadAjaxManager is a persistent control on my page. So, it is my belief that it does not forget the AjaxSettings it knew from before a post-back occurs, but that it probably does forget after a full page refresh. As such, it is my belief that I do need to re-setup settings during each page load, but that I should be looking into my AjaxSettings collection to see if a setting is known already. If the RadDockZone (the control to initiate an ajax request) is unknown, then I add it to the collection, else skip since it's already known.

    protected void Page_Load(object sender, EventArgs e)
    {
        Logger.Info("Page Load");
        RegenerationManager.Instance.RegenerateDockContents();
     
        if (!Page.IsPostBack)
        {
            RegenerationManager.Instance.RegenerateTabs(RadTabStrip1);
            ScriptManager.RegisterStartupScript(Page, Page.GetType(), "KEY01", "ForceResize();", true);
        }
    }

    Here is my current Page_Load event. Should I be treating the AjaxManager similarly to that of the RadTabStrip -- only hooking up controls if its a fresh page, else assuming that they're already known to it (being added through the event described above)?

    I went ahead and played with all of this myself for a bit, but I noticed I was doing something incorrect. What I saw was that the RadDock would fire a post-back event, the hidden update panel would capture the event, but that the RadDock would not update. Interacting with the page again caused it to update, but the update panel I had wrapped was lost (haven't fussed with regenerating it through post-back, so this is expected behavior.) Might be a deeper-seated issue than just improper setting up of the code, though, so I figured I'd come here first.

    Is my reasoning sound? What other gotchas should I be aware of? 

    Thanks.

    Sean
     
  2. Slav
    Admin
    Slav avatar
    1356 posts

    Posted 08 Jul 2011 Link to this post

    Hi Sean,

    As I understand your scenario, you have set up dynamically created RadDockZones and RadDocks in your project. Since you usually have one RadDockZone per RadPane and one RadDock in a RadDockZone, you can wrap the container in which the dock zones are created with RadAjaxPanel or ASP UpdatePanel, in order to ensure that the postback initiated from a RadDock will affect only the specific RadDock. In such case the UpdatePanels, placed inside the docks must be removed to avoid issues caused by nested UpdatePanels.

    Indeed, you cannot AJAX-enable only the RadDock, because in such case it is wrapped with a panel and this leads to problem, since only dock are allowed inside RadDockZone.

    I have attached a sample project that you can build on to achieve the desired effect.

     
    Best wishes,
    Slav
    the Telerik team

    Register for the Q2 2011 What's New Webinar Week. Mark your calendar for the week starting July 18th and book your seat for a walk through of all the exciting stuff we will ship with the new release!

  3. UI for ASP.NET Ajax is Ready for VS 2017
  4. Sean
    Sean avatar
    200 posts
    Member since:
    Nov 2010

    Posted 08 Jul 2011 Link to this post

    Hi,

    I have a few more concerns that I'd like to highlight for future readers (as well as to confirm everything I am doing will work properly!)

    1. What are the benefits of using a RadAjaxPanel compared to an ASP UpdatePanel? 
    2. I have a timer on my page which has an on_tick event. This event may cause a RadDock's UpdatePanel to update. RadAjaxPanel does not have the ability to conditionally update as far as I am aware. Is it possible to gain the benefits of using a RadAjaxPanel while still being allowed to conditionally update server-side?
    3. I have a Microsoft Chart Control as content for my RadDock. This Chart Control has the ability to drill-down (which requires some fairly seriously server-side processing to generate the next level of data.) As such, it is my belief that this functionality disqualifies me from using a RadXMLHttpPanel. Is this belief correct? Is it possible to maintain the ability to update the chart's contents independent of performing a full-lifecycle callback on the RadDockZone + RadDock + Contents? Currently, this is achieved through a call back in the UpdatePanel, but if I need to remove the UpdatePanel and RadXMLHttpPanel seems to not be sufficient... do I have other options?
    4. I am able to create a 1:1 relationship between each RadPane and RadAjaxPanel. The RadAjaxPanel is in charge of only updating the contents of the RadPane and should not have "out-of-panel" experiences. Yet, I also have a RadAjaxManager on my page already performing other tasks. I am wondering if it is more efficient to use the RadAjaxManager to achieve this functionality rather than manually creating my own RadAjaxPanel. How can I tell which is more efficient, or when the breaking point might be reached?

    As always, thank you and kind regards.

    Sean Anderson

    EDIT: Hi, as expected, I am encountering an issue between my choices of Panel vs UpdatePanel vs RadAjaxPanel. My requirements:

    1) Be able to called .Update() from Server-Side, or an equivalent means of updating controls. I believe this disqualifies my use of Panel and RadAjaxPanel, but I would like to make sure. I looked at this thread and saw that there was a hack-ish way to expose the RadAjaxPanel's Update method. Here is the code I am attempting to replicate. Does Telerik believe it would be possible to extend this hack to my scenario?

    /// <summary>
    /// Timer ticks once a minute to check for graphs which need to be refreshed.
    /// Each dock contains the ability to refresh itself locally. If this is enabled,
    /// then the timer monitors that countdown. Otherwise, if there is a global refresh,
    /// then each dock which is not refreshed locally will be updated. This is to prevent
    /// a graph from updating twice in one tick.
    /// </summary>
    protected void Timer1_Tick(object sender, EventArgs e)
    {
        Logger.InfoFormat("Timer tick at {0}", DateTime.Now);
        IList<CormantRadDock> docks = DashboardLayoutManager.Instance.RegisteredDocks;
        docks.Where(dock => dock.RefreshEnabled).ToList().ForEach(dock => dock.DoTimerRefreshTick());
     
        GlobalSettings globalSettings = RadControlManager.GetStates<GlobalSettings>();
        if (globalSettings.RefreshEnabled)
        {
            globalSettings.MinutesUntilRefresh -= 1;
            Logger.InfoFormat("Global auto refresh has {0} minutes until refresh.", globalSettings.MinutesUntilRefresh);
     
            if (int.Equals(globalSettings.MinutesUntilRefresh,0))
            {
                Logger.Info("Global auto refresh - refreshing.");
                globalSettings.MinutesUntilRefresh = globalSettings.RefreshInterval;
     
                //Don't refresh docks globally if they are refreshing themselves locally.
                //TODO: Figure out how to re-implement this.
                //foreach (CormantRadDock dock in docks.Where(dock => !dock.RefreshEnabled))
                //{
                //    dock.RefreshContent(ForceCacheRefresh.False);
                //    dock.UpdatePanel.Update();
                //}
            }
        }
    }

    I have 0+ dynamically created controls which need updating based off of saved settings. 

    Now, in my eyes, I believe I should be using strictly UpdatePanels to achieve my functionality. In my first attempt I did just that. However, I noticed two things, and I would like to see how large of an issue these things are:

    I would like to display a RadAjaxLoadingPanel over my RadDocks when they are being updated. UpdatePanels, obviously, do not inherently have the ability to do this. Do I need to create a RadAjaxLoadingPanel every time I create an UpdatePanel? So much nesting... it would be nice to let RadAjaxManager handle all of this, but without being able to forcibly update RadAjaxPanels... (EDIT: I figured out how to do it from another post. I've modified this code slightly to use correct syntax. It is not recc'ed unless you HAVE to use UpdatePanels, but this worked right out of the bag for me --
    <script language="javascript" type="text/javascript">
      
        var loadingPanel = "";
        var pageRequestManager = Sys.WebForms.PageRequestManager.getInstance();
        var postBackElement = "";
        pageRequestManager.add_initializeRequest(initializeRequest);
        pageRequestManager.add_endRequest(endRequest);
      
        function initializeRequest(sender, eventArgs)
        {
            loadingPanel = $find("<%= RadAjaxLoadingPanel1.ClientID %>");
            postBackElement = eventArgs.get_postBackElement().id;
            loadingPanel.show(postBackElement);
        }
      
        function endRequest(sender, eventArgs)
        {
            loadingPanel = $find("<%= RadAjaxLoadingPanel1.ClientID %>");
            loadingPanel.hide(postBackElement);
        }
      
    </script>

    UpdatePanels do not have a height property, nor do they expose a cssClass property. The UpdatePanel shrinks to wrap around its child control. Unfortunately, its child control is a RadDockZone. This RadDockZone has its height unset so that it will expand to fill the height of the pane it is existing in. Wrapping the RadDockZone in an UpdatePanel causes the RadDockZone's height to be in the 0-1px range. The obvious fix is to apply CSS to fix the issue, but since my UpdatePanels are generated dynamically I am unable to apply CSS by ID. CSS by class has no effect / can't seem to target the UpdatePanel. (EDIT: If you're having this issue check out this blog post. The nStuff suite has a StyledUpdatePanel which is a simple extension to give it the cssClass property)

    So, after all this writing, it seems that I've actually managed to accomplish most of what I was hoping for. I'm going to leave all this information up for others to find, and perhaps Telerik could answer my lingering questions, but overall I'm happy with the way I am going with this solution.

    Thanks

  5. Answer
    Slav
    Admin
    Slav avatar
    1356 posts

    Posted 13 Jul 2011 Link to this post

    Hello Sean,

    RadAjaxManager and RadAjaxPanel are based on MS AJAX and generate asp:UpdatePanels on the fly around the updated controls.  The RadAjaxPanel works almost exactly like UpdatePanels, however with RadAjaxManager you can ajaxify codeless 90% of the scenarios instead of using plain UpdatePanels with Triggers which is needed in case you want particular control to fire ajax call and particular control(s) to be updated in this specific ajax call. Note that when using RadAjaxManager to ajax enable controls that are created dynamically, you should set the AjaxSettings in Page_PreRender event.

    Truly, in this scenario RadXMLHttpPanel cannot be applied, you may use UpdatePanel, RadAjaxPanel or RadAjaxManager. In all of these cases please keep in mind that the whole lifecycle is executed and only certain parts of the page are silently updated. This behavior can't be avoided.

    To prevent "out-of-panel" experiences RadAjaxManager will be more efficient, as you guessed, because you can visually and codeless (in Visual Studio design-time) define which elements should initiate AJAX requests and which elements should be updated.

    RadAjax controls do not contain a method equivalent to .Update(), but you may send ajax request via this approach.

    As you found out, to display the loading panel explicitly over an element, when UpdatePanel is used for ajaxification, just call the Show method client-side. The other approach is to switch to RadAjaxManager.

    I hope your project is going well.

    Best wishes,
    Slav
    the Telerik team

    Register for the Q2 2011 What's New Webinar Week. Mark your calendar for the week starting July 18th and book your seat for a walk through of all the exciting stuff we will ship with the new release!

Back to Top