Bug: Changing DragDropMode in run time doesn't behave as expected

15 posts, 3 answers
  1. BENN
    BENN avatar
    62 posts
    Member since:
    Dec 2011

    Posted 21 Apr 2016 Link to this post

    We are currently replacing an old Infragistics docking manager with your control, and with the old code, we've prevented the floating of windows.

    However, the user could still move panes around to a different location, and change the layout (Just like with DragDropMode is set to Deferred).

     

    I would like to support the legacy mode (Which will be the default) which will behave just like the Deferred DragDropMode. I also want the user to be able to change an option in the program, which will change the DragDropMode to Immediate.

     

    This, however, doesn't work as expected...

    If changing from Immediate to Deferred:

    * Docked panes are not movable (no compass and no deferred adorner is being shows)

    * Floating panes that are being docked do have the compass and the deferred adorner, when you try to move them after they were docked. 

     

    If you change is back from Deferred to Immediate:

    * Panes that you could not move can be moved (and then become floating) again/

    * The panes that did have  the compass and the deferred adorner, don't move when you try to drag them. However, when you release the mouse button, then the start moving with the mouse pointer... without any mouse button pressed.

     

    Thanks

  2. BENN
    BENN avatar
    62 posts
    Member since:
    Dec 2011

    Posted 25 Apr 2016 in reply to BENN Link to this post

    I've debugged the controls using the source code, and I've concluded that.

    RadPane.UdateAllowDrag() is being called on PaneLoaded, which happens when I drag a floating pane into the Docking area.

    In this case, when the DragDropMode is set to Deferred, then AllowDrag is set to True (with the call of DragDropManager.SetAllowDrag)

    This is why that pane does have the Deferred Drag Adorner (The Drag Cue), while other panes doesn't.

     

    On the other hand, when I change the DragDropMode to be Immediate again, then that pane is left with AllowDrag set to true, and it is registered to the DragDropManager events, which causes the second problem.

     

    In my opinion, the RadPane.UpdateAllowDrag() should be called also when the DragDropMode is changed.

  3. BENN
    BENN avatar
    62 posts
    Member since:
    Dec 2011

    Posted 25 Apr 2016 in reply to BENN Link to this post

    I've opened a bug report
  4. Polya
    Admin
    Polya avatar
    235 posts

    Posted 25 Apr 2016 Link to this post

    Hello Benn,

    Thank you for pointing these problems out and logging them in Feedback Portal.

    We are aware of some of them related to switching the RadDocking.DragDropMode in runtime and with the Deferred mode. You can also track their progress in our Feedback Portal: http://feedback.telerik.com/Project/143/Feedback/Details/113624-when-dragdropmode-is-set-to-deferred-and-the-layout-is-changed-and-saved-some-pan, http://feedback.telerik.com/Project/143/Feedback/Details/125238-the-compasses-dont-disappear-when-reordering-the-panes-in-dragdropmode-deferred

    I've updated your Telerik Points as a small token of appreciation for your efforts.

    Regards,
    Polya
    Telerik
    Do you need help with upgrading your AJAX, WPF or WinForms project? Check the Telerik API Analyzer and share your thoughts.
  5. BENN
    BENN avatar
    62 posts
    Member since:
    Dec 2011

    Posted 26 Apr 2016 in reply to Polya Link to this post

    I'm guessing that the bug with the saved layout, and panes that are not being rendered correctly is referring to the forum thread:

    http://www.telerik.com/forums/saved-layout-does-not-fill-empty-space

     

    Am I right?

     

    If so, I've looked at the layout xml, and it seems that there is empty split container (without any panes or even groups) inside another split container.

     

    Is the solution of removing all the empty split containers on the save layout is a good solution? (meaning, it will not cause problems)

     

    I'm using the following code:

    private void saveLayout()
    {
        XDocument doc = null;
        using (MemoryStream ms = new MemoryStream())
        {
            this.radDocking.SaveLayout(ms, true);
            ms.Seek(0, SeekOrigin.Begin);
            doc = XDocument.Load(ms);
        }
     
        removeEmptySplitContainers(doc.Root);
     
        using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly())
        {
            using (var isoStream = storage.OpenFile("RadDocking_Layout.xml", FileMode.Create))
            {
                doc.Save(isoStream);
            }
        }
    }
     
    private void removeEmptySplitContainers(XElement parent)
    {
        var splitContainers = parent.Descendants(XName.Get("RadSplitContainer")).ToList();
     
        foreach (var splitContainer in splitContainers)
        {
            if (!splitContainer.Descendants(XName.Get("RadPaneGroup")).Any())
            {
                // Remove Empty split containers
                splitContainer.Remove();
            }
        }
    }

     

     

    My assumption is that any SplitContainer that doesn't contain any RadPaneGroup is a leftover that shouldn't be there.

    Is this solution safe?

     

    Thanks.

  6. BENN
    BENN avatar
    62 posts
    Member since:
    Dec 2011

    Posted 27 Apr 2016 in reply to BENN Link to this post

    In addition to my previous question, is there a way to disable panes reordering in Deferred mode?

    AllowDragReorder is not effective in this case. I've debugged the code, and I see that the DragCompleted event never reaches the pane on certain cases, and it happens because the Grid that is being registered to the DragDropManager events is being removed from the visual and logical tree.

  7. Polya
    Admin
    Polya avatar
    235 posts

    Posted 28 Apr 2016 Link to this post

    Hi Benn,

    Regarding your first question about the empty RadSplitContainers being saved in the xml - this might be caused by the fact that the specific split container has SerializationTag set while its child elements do not. This causes our save/load layout implementation to persist only the split container and not its children.
    Removing the empty RadSplitContainers should not cause any issues, so give it a try and let us know if it works in this scenario. Keep in mind that when this xml is loaded - first the RadDocking will be cleared and then the xml will be loaded - and if there are empty split containers tags we will still create (or take from the cache) a corresponding split container and add it in the RadDocking.

    Regarding the second question - is there a way to disable panes reordering in Deferred mode?
    I've prepared a sample project demonstrating how to achieve that for a RadPane that has the property CanFloat set to false.
    The approach consists of adding handler to the DragInitialize method and canceling it if the RadDocking.ActivePane has CanFloat = false. Similarly, you can use a property best suitable for your scenario:
    public MainWindow()
    {
        InitializeComponent();
      
        DragDropManager.AddDragInitializeHandler(this.radDocking1, this.OnDragInitialize, true);
        DragDropManager.AddDragInitializeHandler(this, this.OnDragInitialize);
    }
      
    private void OnDragInitialize(object sender, DragInitializeEventArgs e)
    {
        if (sender is MainWindow)
        {
            // Raise drag event from radpane, started from overlay
            this.NonDraggablePane.RaiseEvent(e);
        }
        else
        {
            if(sender is RadDocking)
            {
                var selectedPane = (sender as RadDocking).ActivePane as RadPane;
      
                if(!selectedPane.CanFloat)
                {
                    e.Handled = true;
                    e.Cancel = true;
                }
            }
        }
    }

    Please find the project attached. Hope this helps.

    Regards,
    Polya
    Telerik
    Do you need help with upgrading your AJAX, WPF or WinForms project? Check the Telerik API Analyzer and share your thoughts.
  8. BENN
    BENN avatar
    62 posts
    Member since:
    Dec 2011

    Posted 30 Apr 2016 in reply to Polya Link to this post

    Actually, my last question was on preventing reordering (and not the placement of panes in another location using the compass).

    I'm trying to workaround the bug that the compass don't disappear in deferred mode.

  9. BENN
    BENN avatar
    62 posts
    Member since:
    Dec 2011

    Posted 01 May 2016 in reply to BENN Link to this post

    I have a "workaround" for the original bug (Where the compass don't disappear on deferred mode), and I just want to know the risks, if any.

    In the RadPane, you have the function SetAllowDrag:

    private void UpdateAllowDrag()
    {
        if (!Design.Designer.IsInDesignMode)
        {
            var dock = this.GetParentDocking();
            var dragDropMode = dock != null ? dock.DragDropMode : default(DockingDragDropMode);
            var child = VisualTreeHelper.GetChildrenCount(this) > 0 ? VisualTreeHelper.GetChild(this, 0) asFrameworkElement : null;
            if (child != null && this.IsPinned)
            {
                DragDropManager.SetAllowDrag(child, dragDropMode == DockingDragDropMode.Deferred);
            }
     
            var group = this.PaneGroup;
            if (group != null && group.PaneHeader != null && this.IsPinned)
            {
                DragDropManager.SetAllowDrag(group.PaneHeader, dragDropMode == DockingDragDropMode.Deferred);
            }
        }
    }


    This function fails on some cases, since child is being removed from the visual tree, and from its parent (the RadPane), hence the DragDropCompleted event of is not bubbling to the RadPane.

    If I set the allow drag on the RadPane itself, other than its child, meaning:
    DragDropManager.SetAllowDrag(this, dragDropMode == DockingDragDropMode.Deferred);

    Then I see that the compass disappears, and that the DragDropCompleted event is being received by the RadPane. What are the risks of this change, if any? (for example, null reference, memory leaks, other types of bugs).

    Thank.
  10. Answer
    Nasko
    Admin
    Nasko avatar
    681 posts

    Posted 03 May 2016 Link to this post

    Hello Benn,

    Actually, once our code was setting the AllowDrag to the Pane itself as you have found out:
    DragDropManager.SetAllowDrag(this, dragDropMode == DockingDragDropMode.Deferred);

    However, that will cause another issue - when there are any UI Elements placed inside the Pane as a content the Pane will be able to be dragged by clicking on this UI Elements. Because of that we fix that issue by setting the AllowDrag to the child. Because of that we do not recommend you to use the workaround you have found. Unfortunately, we could not suggest you any other proper workaround, so please follow the item if you haven't done it yet and as soon as the issue gets fixed you will be notified.

    We would like also to ask you some questions regarding the following item:
    http://feedback.telerik.com/Project/143/Feedback/Details/113624-when-dragdropmode-is-set-to-deferred-and-the-layout-is-changed-and-saved-some-pan

    Indeed as you have found out the issue is caused by the empty SplitContainers that are saved inside the XML file. However, we investigated the issue further and it seems that is has already been fixed with version Q2 2013 - since that version we are no longer loading the empty SplitContainers and because of that the issue should not be observed. Could you please confirm that you are observing the issue with our latest released version Q1 2016 SP1? If you are please, sent us a sample project that reproduces it.

    We are looking forward to hearing from you.

    Regards,
    Nasko
    Telerik
    Do you need help with upgrading your AJAX, WPF or WinForms project? Check the Telerik API Analyzer and share your thoughts.
  11. BENN
    BENN avatar
    62 posts
    Member since:
    Dec 2011

    Posted 03 May 2016 in reply to Nasko Link to this post

    Are you sure this bug is fixed? It is marked  as approved, not fixed.

    Anyway, here is the project:

    https://onedrive.live.com/redir?resid=F2DC329C215CDEF1!584885&authkey=!ALDTMhKFVW6dG5U&ithint=file%2crar

     

    I've compiled it with the 2016.q1.217.40 binaries, and I've removed them from the rar (in order to protect your assemblies from misuse by someone else).

     

    Just follow the instructions at:

    http://www.telerik.com/forums/saved-layout-does-not-fill-empty-space

     

    Drag the Boven pane to the left side, and then drag the Onder pane to the pane side, under the Boven pane.

    Close the application and run it again. The layout will be loaded from the xaml, leaving an empty space at the right side due to an empty split container.

     

  12. BENN
    BENN avatar
    62 posts
    Member since:
    Dec 2011

    Posted 04 May 2016 in reply to BENN Link to this post

    You are correct, setting the Allow Drag on the pane itself does cause the problem you've mentioned.
    I have noticed that the problem seems to happen only for panes in the Document Host (and I didn't understand why)... So I've debugged it a little further, and found out that since the re-ordering is removing and adding the pane from the group, a ClearContainerForItemOverride and then PrepareContainerForItemOverride are being called.

    The first one is setting the IsInDocumentHost to false, and the second one to true again, which causes the template to be applied again. This is because of :

    private void OnIsInDocumentHostChanged(bool oldValue, bool newValue)
    {
        this.UpdateTemplate();
        this.UpdateMenuCommands();
        this.OnStateChange();
    }

     

    Since tabs reordering does not change the IsInDocumentHost,  then this is just a side affect that should be ignored,

     

    I have coded a workaround, which is ugly, and not considered bad coding, so if you can think of a better solution, or see any problem with this solution, then please comment.

     

    I have created an internal bool inside the RadPane, called IsBeingReordered (default value is false).

    Now the OnIsDocumentHostChanged code is:

    private void OnIsInDocumentHostChanged(bool oldValue, bool newValue)
    {
        if (IsBeingReordered)
            return;
     
        this.UpdateTemplate();
        this.UpdateMenuCommands();
        this.OnStateChange();
    }

     

     

    And the RadPaneGroup.ReorderTwoNeighbourPanes code changed to this"

    private void ReorderTwoNeighbourPanes(RadPane reorderedPane, RadPane otherPane, int otherPaneIndex)
    {
        var firstRect = new Rect(ApplicationHelper.TransformToScreenRoot(reorderedPane).Transform(new Point()), reorderedPane.RenderSize);
        var secondRect = new Rect(ApplicationHelper.TransformToScreenRoot(otherPane).Transform(new Point()), otherPane.RenderSize);
     
        this.lastPairOfReorderedPanes = new LastPairOfReorderedPanes(reorderedPane, otherPane, firstRect, secondRect);
     
        try
        {
            reorderedPane.IsBeingReordered = true;
            this.Items.Remove(reorderedPane);
            otherPaneIndex = Math.Max(Math.Min(this.Items.Count, otherPaneIndex), 0);
            this.Items.Insert(otherPaneIndex, reorderedPane);
        }
        finally
        {
            reorderedPane.IsBeingReordered = false;
        }
        ////Trace.TraceAtomicFeature(FeatureClass.DragDrop, "DragReorderPanes", typeof(RadDocking), this.Docking.Name, TraceLevel.Normal);
    }

     

    By this way, I prevent the extra ApplyTemplate calls.

  13. Answer
    Nasko
    Admin
    Nasko avatar
    681 posts

    Posted 04 May 2016 Link to this post

    Hello Benn,

    Thank you for the provided sample project in your previous response. Using it we were able to reproduce again the issue on our side - it seems it has been partially fixed. I am glad to inform you that we have decided to rise the priority of that issue and currently our development team is working on it - as soon as it gets fixed if you have followed the item you will be notified.

    As about your latest response. We checked the workaround you have found and it seems a nice one. However, please notice that we cannot guarantee that it will work flawlessly in different scenarios and you might need to test it further.

    We hope the provided information will be helpful for you.


    Regards,
    Nasko
    Telerik
    Do you need help with upgrading your AJAX, WPF or WinForms project? Check the Telerik API Analyzer and share your thoughts.
  14. BENN
    BENN avatar
    62 posts
    Member since:
    Dec 2011

    Posted 04 May 2016 in reply to Nasko Link to this post

    I have tested my solution a little further, and there are some cases that it doesn't work (Since the reordering is being done on different events, like TabStripPanel Drop handler, or RadPaneGroup Drop handler (There is maybe another one or two more handlers that I forgot to mention).

    In this case, I'm going something like:

    reorderedPane.IsBeingReordered = reorderedPane.IsInDocumentHost == radPaneGroup.IsInDocumentHost;

    (In order to still support cases when a pane is being moved from the document host to a different location, or vice versa);
    And after those fixes, it seemed to be working correctly on all cases I've tested. I just don't like the fact hat I'm setting and resetting a flag.

  15. Answer
    Nasko
    Admin
    Nasko avatar
    681 posts

    Posted 06 May 2016 Link to this post

    Hello Benn,

    Thank you again for sharing your solution with us. From the provided description and code of the solution it seems to be a good one and we will definitely check it when the time for fixing the issue comes.

    Meanwhile if you have any additional questions or concerns regarding Telerik controls, please do not hesitate to contact us.

    Regards,
    Nasko
    Telerik
    Do you need help with upgrading your AJAX, WPF or WinForms project? Check the Telerik API Analyzer and share your thoughts.
Back to Top