ForbiddenZones bug?

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

    Posted 14 Jun 2011 Link to this post

    Hi Telerik,

    Could you please clarify if this is expected behavior?

    I am programatically setting the ForbiddenZones property of every dock on my page. I do so like this:

    /// <summary>
    /// Shows where docks can/can't be moved. Forbidden zones are all DockZone's with Docks.
    /// </summary>
    private void SynchForbiddenZones(RadDockLayout dockLayout)
    {
        Logger.Info("Synching forbidden zones");
        IEnumerable<CormantRadDock> docks = dockLayout.RegisteredDocks.OfType<CormantRadDock>();
     
        foreach (CormantRadDock dock in docks)
        {
            List<string> forbiddenZones = new List<string>();
            foreach (CormantRadDock otherDock in docks.Where(otherDock => otherDock != dock && !otherDock.GetState().Closed))
            {
                forbiddenZones.Add(otherDock.DockZoneID);
                forbiddenZones.Add(otherDock.DockZoneID.Replace("RadDockZone_", "")); //Why is this necessary?
            }
            dock.ForbiddenZones = forbiddenZones.ToArray();
        }
    }

    I have found that there is a discrepancy between how Telerik's Client and Server code interpret ForbiddenZones. 

    If I leave my forbidden zones as just "DockZoneID" then this code works fine:

    function OnClientDragStart(dock) {
        var forbiddenZones = dock.get_forbiddenZones();
        for (var zoneId in forbiddenZones) {
            var zone = $find(forbiddenZones[zoneId]);
            if (zone != null) {
                var zoneElement = zone.get_element();
                Sys.UI.DomElement.addCssClass(zoneElement, "zoneDropNotOk");
            }
        }
    }
     
    function OnClientDragEnd(dock) {
        var forbiddenZones = dock.get_forbiddenZones();
     
        for (var zoneId in forbiddenZones) {
            var zone = $find(forbiddenZones[zoneId]);
            if (zone != null) {
                var zoneElement = zone.get_element();
                Sys.UI.DomElement.removeCssClass(zoneElement, "zoneDropNotOk");
            }
        }
    }

    but when I drag a dock onto an already populated dock zone, even though the zone glows red, I am still able to drop the dock onto the dock zone.

    Yet, observe that if I strip of the "RadDockZone_" header -- thus making it the DockZone's UniqueName -- now the dock is unable to dock onto the dockzone in question. 

    Yet, observe that if I only add the DockZone's UniqueName property to the dock's ForbiddenZone array that the above JavaScript stops functioning.

    The client side appears to care about the ID of the zone, the server side cares about the UniqueName. If this is intended, why? It is a hassle to comment why I am storing two values when only one is necessary to determine uniqueness.
  2. Answer
    Pero
    Admin
    Pero avatar
    1156 posts

    Posted 16 Jun 2011 Link to this post

    Hi Sean,

    The ForbiddenZones and AllowedZones properties of the RadDock control expect a string array of RadDockZone's UniqueNames where the dock is forbidden and allowed to dock respectively. On the client-side again the get_forbiddenZones(); property will return the array with UniqueNames of all zones where the dock is forbidden to dock. RadDock's DockZoneID property stores the ClientID of the zone where the dock is docked to, which is not necessarily the same as the zone's UniqueName. The UniqueName if it is not explicitly set is equal to the server ID of the zone.
    So use UniqueNames to specify forbidden and allowed zones. In this case the JS code will not work because the $find shortcut expects a ClientID of the zone and not a UniqueName.
    You can set the ClientID of the zone to its UniqueName and then it will be enough to add only the DockZoneID of the dock as a forbidden zone, but I am not sure if this won't break something else in your application.

    Best wishes,
    Pero
    the Telerik team

    Browse the vast support resources we have to jump start your development with RadControls for ASP.NET AJAX. See how to integrate our AJAX controls seamlessly in SharePoint 2007/2010 visiting our common SharePoint portal.

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

    Posted 16 Jun 2011 Link to this post

    I found that by not setting the UniqueName field everything worked as expected. Sounds like just clashing IDs.
  5. Sean
    Sean avatar
    200 posts
    Member since:
    Nov 2010

    Posted 13 Jul 2011 Link to this post

    Hi,

    I would like some more information with regards to the timing of setting up ForbiddenZones. Here is what my scenario is and what I am experiencing. Of note, my implementation has evolved past using the RadDockLayout control. I am not sure if that is relevant to my issues or not, however.

    I allow the user to dynamically add a dock to a dockZone. I create this like so:

    function OnClientDropping(sender, eventArgs) {
        eventArgs.set_cancel(true);
        sender.clearSelection();
        previousZone = null;
     
        var sourceItem = eventArgs.get_sourceItem();
        var droppedID = eventArgs.get_htmlElement().id;
     
        var indexOfID = droppedID.indexOf("RadDockZone");
        var uniqueID = droppedID.substr(0, indexOfID).replace(/_/g, "$");
        var dockZoneID = droppedID.substr(indexOfID);
     
        if (droppedID.indexOf("RadDockZone") != -1) {
            if ($find(droppedID).get_docks().length == 0) {
                dockZoneDroppedOnID = droppedID;
     
                var eventData = {};
                eventData["sourceItemText"] = sourceItem.get_text();
                eventData["sourceItemValue"] = sourceItem.get_value();
                eventData["listBoxID"] = sender.get_id();
                var uniqueDockZoneID = uniqueID.concat(dockZoneID);
     
                if (queue.length == 0) {
                    queue.push(uniqueDockZoneID);
                    queue.push(eventData);
                    $find(ajaxManagerID).ajaxRequestWithTarget(uniqueDockZoneID, $.toJSON(eventData));
                }
                else {
                    queue.push(uniqueDockZoneID);
                    queue.push(eventData);
                }
            }
        }
        else {
            dockZoneDroppedOnID = "";
        }
    }

    What I'm doing is passing the event off to the control which is actually doing the work. My RadListBox does not change state at all after the drag-and-drop, but the area being dropped onto certainly does. 

    //Inside of my class, CormantRadDockZone, which inherits from RadDockZone:
    public void RaisePostBackEvent(string eventArgument)
    {
        ProcessDragAndDrop(ID, eventArgument);
    }
     
    public void ProcessDragAndDrop(string dockZoneID, string json)
    {
        CormantRadDockZone dockZone = DashboardLayoutManager.Instance.GetDockZoneByID(dockZoneID);
     
        if (!object.Equals(dockZone, null) && !dockZone.Docks.Any())
        {
            DroppedItem droppedItem = JsonConvert.DeserializeObject<DroppedItem>(json);
     
            if (object.Equals(droppedItem.ReportType, Reports.None))
            {
                CreateSplitterAndTwoPanes(dockZone, droppedItem);
            }
            else
            {
                CreateDockAndChart(dockZone, droppedItem);
            }
        }
    }

    /// Creates the RadDock and Contents when dropping a graph onto the page.
    /// Attaches the newly created RadDock to the specified DockZone.
    /// </summary>
    public static void CreateDockAndChart(RadDockZone dockZone, DroppedItem droppedItem)
    {
        if (!object.Equals(dockZone, null) && !dockZone.Docks.Any())
        {
            CormantRadDock dock = new CormantRadDock(droppedItem);
            dock.CreateContent();
            dockZone.Controls.Add(dock);
            dock.PrepareChartForDisplay();
            dock.RefreshGraphTitle();
        }
    }

    Of note, I am not using dock.Dock(dockZone). I am unable to use this functionality without the presence of a RadDockLayout control. As such, I simply add the dock to the dockZone's control collection. I do see dockZone.Docks() increment to 1 after doing so.

    Now, during Page_SaveStateComplete:

    DashboardLayoutManager.Instance.RegisteredDocks.ToList().ForEach(dock => dock.SynchForbiddenZones());

    /// <summary>
    /// Shows where docks can/can't be moved. Forbidden zones are all DockZone's with Docks.
    /// So, a dock can move to any other dockZone that does not have a control. Those are the allowed zones.
    /// Its own spot is allowed so that the highlighting looks correct -- but it is not necessary.
    /// </summary>
    public void SynchForbiddenZones()
    {
        IEnumerable<CormantRadDockZone> dockZonesWithDocks = DashboardLayoutManager.Instance.RegisteredDockZones.Where(dockZone => dockZone.Docks.Any());
        ForbiddenZones = dockZonesWithDocks.Select(dockZone => dockZone.ID).ToArray();
        Logger.DebugFormat("Forbidden zones for dock: {0} are {1}", ID, ForbiddenZones.ToString());
    }

    Under this scenario:
    2x DockZones which existed during last page lifecycle.
    1x Dock (DOCK1) on DockZone which existed during last page lifecycle.
    1x Dock (DOCK2) created during Page_Load and added to DockZone.

    My RegisteredDocks is 2, and I set each of their forbidden zones to both of the dockZones (intended and working fine!).

    At this point, after the page is rendered to the user, I am still able to drag DOCK1 onto DOCK2's dockZone. I thought this might've been something weird and small, but this code doesn't patch the issue:

    function OnClientDockPositionChanging(sender, eventArgs) {
        var dockZoneID = sender.get_dockZoneID();
     
        if (dockZoneID != "") {
            var dockZone = $find(dockZoneID);
            if (dockZone.get_docks().length != 0) {
                eventArgs.set_cancel(true);
            }
        }
    }

    So, I'm at a bit of a loss.

    Server-side DOCK2's dockZone said it has 1 Docks, but client-side it says it has 0. I still see DOCK2's dockZone has an allowed zone, even though it is marked as forbidden. Refreshing the page fixes this issue. I am not able to drag DOCK2 anywhere (it's own dockZone is forbidden to prevent postbacks when the user just clicks it accidentally... and DOCK1's dockZone is correctly marked as forbidden).

    I believe my problem is this: Since I targeted DOCK2's dockZone for dock creation, but DOCK1's dockZone needed to update properties (its docks' forbidden zones property), there is nothing telling DOCK1's dockZone to pay attention to the changes which have occurred.

    Unfortunately... I really do not want to update every panel on my page every time a dock drops onto the page. This would completely defeat the purpose of having isolated zones. If this is really what is happening then I could use a better solution. I thought I might be able to replicate some functionality I already have for highlighting zones when the user is dragging a RadListBoxItem across the screen, but it appears that this is not possible with RadDock's OnClientDrag event. I only want to highlight a zone when it is being dragged over, not highlight all allowed zones while dragging. 

    I have experienced no other issues with my implementation except for this little quirk, so I'm hoping it's a simple fix.

    Let me know if I'm unclear at all. Thanks.

    Sean
  6. Pero
    Admin
    Pero avatar
    1156 posts

    Posted 20 Jul 2011 Link to this post

    Hi Sean,

    As I said in my previous reply the ForbiddenZones and AllowedZones properties of the RadDock control expect an array of the UniqueNames of the zones where the dock will be forbidden and allowed to dock, respectively. In your case I suppose you don't explicitly set the UniqueName property of the zones, which causes the server ID to be used as a UniqueName.
    The ForbiddenZones property is set before the rendering phase, so in terms of page lifecycle everything should be OK.

    The OnClientDockPositionChanging event is fired just before the dock changes its position, and the dock is undocked. This means that the number of the docks in the zone will be equal to the number of docks minus one, when checking it in this event. So maybe you should change the event handler to check for if(dockZone.get_docks().length != -1).

    This is the client method of the RadDockZone that checks whether a dock should be allowed to dock in a certain zone:
    canDrop: function(dock) {
        var allowedZones = dock.get_allowedZones();
        var uniqueName = this.get_uniqueName();
        return ((dock.get_dockMode() & Telerik.Web.UI.DockMode.Docked) > 0 &&
                    Array.indexOf(dock.get_forbiddenZones(), uniqueName) < 0 &&
                    (allowedZones.length == 0 || Array.indexOf(allowedZones, uniqueName) >= 0));
    }
    You could try to debug it to see if the forbidden zones property of the dock contain the zone in question.
    If the problem persists please send us a sample project so we could try to debug the issue locally. You could also provide a live URL.

    Regards,
    Pero
    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
UI for ASP.NET Ajax is Ready for VS 2017