Drag and drop between treeviews

6 posts, 0 answers
  1. Christian Burkhardt
    Christian Burkhardt avatar
    23 posts
    Member since:
    Feb 2010

    Posted 21 Jul 2011 Link to this post

    Hi Telerik,

    I have a user control with a RadTreeView which is open in multiple docking panes.
    The user can  drag nodes, between the trees of the floating panes.

    Since I reuse the usercontrol with the RadTreeView, when doing a drag and drop the same PreviewDragEnded event handler is called for both the source tree & target tree.
    First the PreviewDragEnded event of the source tree from which the node is being dragged is called.
    Next the PreviewDragEnded event of the target tree onto which the item is being dropped is called.

    I have some questions in the code below:
    //How do I know that this is the event of the source tree from which the item is dragged,
          and remove the item from the viewmodel (datacontext) items? 
    //How do I know that this is the event of the target tree in which the item is dropped and
          add the item to the view model (datacontext)?
    //How can I get a reference to both source tree datacontext, target tree datacontext in here,
          so I can call Remove, Add methods on them?

    Please keep in mind that I need to know also the DropPosition, and Item onto which is being dropped.
    Also, I can't use the default behavior of RadTreeView since I need to call Add/Remove methods on my viewmodel explicitly that do more processing than just adding/removing to a collection.
    Also I am required to allow the user to re-order chapters using drag & drop, in the RadTreeView. 
    How can I detect when I'm in a self-drag & drop scenario?

     One thought, crossing my mind was using sourceTree != e.TargetDropItem.ParentTree, but the problem is that, if I drop at the end of a tree, then e.TargetDropItem is null.


    private void chaptersTree_PreviewDragEnded(object sender, RadTreeViewDragEndedEventArgs e)
           {
               //Get the RadTreeView
               RadTreeView sourceTree = e.OriginalSource as RadTreeView;
               //Get the dragged DataItem
               Chapter draggedDataItem = e.DraggedItems[0] as Chapter;
               RadTreeViewItem destinationItem = e.TargetDropItem;
     
     
               //How do I know that this is the event of the source tree from which the item is dragged, and remove the item from the viewmodel items?
               //How do I know that this is the event of the target tree in which the item is dropped?
               //How can I get a reference to both source tree datacontext, target tree datacontext in here, so I can call Remove, Add methods on them?
     
               e.Handled = true;
          }


  2. Christian Burkhardt
    Christian Burkhardt avatar
    23 posts
    Member since:
    Feb 2010

    Posted 21 Jul 2011 Link to this post

    One solution which might work I think is to use something like:

    private RadTreeViewDragEndedEventArgs dragEndedEventArgs;
      
      
    void TreeView_PreviewDragEnded(object sender, Telerik.Windows.Controls.RadTreeViewDragEndedEventArgs e)
    {
     this.dragEndedEventArgs = e;
        e.Handled = true;
    }
      
      
    private void OnDropInfo(object sender, DragDropEventArgs e)
    {
        if (e.Options.Status == DragStatus.DropComplete)
        {
            //detecting node reordering
            bool isSelfDragDrop = false;
            RadTreeView sourceTree = (e.Options.Source as RadTreeViewItem).ParentTreeView;
            RadTreeView destinationTree = null;
            if (e.Options.Destination is RadTreeView)
            {
                destinationTree = e.Options.Destination as RadTreeView;
            } else if (e.Options.Destination is RadTreeViewItem)
            {
                destinationTree = (e.Options.Destination as RadTreeViewItem).ParentTreeView;
            }
                                                                                   
            if ((sourceTree == null || destinationTree == null) || (this.dragEndedEventArgs == null))
            {
                return; //this should not normally happen if we allow drag & drop just between trees.
            }
      
      
            if (sourceTree == destinationTree)
            {
                isSelfDragDrop = true;
            }
      
      
            //Get the drop position
            DropPosition dropPosition = this.dragEndedEventArgs.DropPosition;
            //Get the dragged DataItem
            DataItem draggedDataItem = this.dragEndedEventArgs.DraggedItems[0] as DataItem;
            //Get the destination DataItem
                    DataItem destinationItem = null;
                    bool isDroppedAtEndOfTree = false;
                    if (e.Options.Destination is RadTreeViewItem)
                    {
                        destinationItem = this.dragEndedEventArgs.TargetDropItem.Item as DataItem;   
                    } else if (e.Options.Destination is RadTreeView && insertPosition == TreeInsertPosition.Inside)
                    {
                        //if we're here, it means that we're trying to make the dragged element the last node of the tree
                        //in that case, the destination is not the last tree node, with DropPosition=After,
                        //instead it is the RadTreeView itself with DropPosition = Inside.
                        isDroppedAtEndOfTree = true;
                    }  
      
            var sourceViewModel = sourceTree.DataContext;
            var parentViewModel = destinationTree.DataContext;
      
      
            //remove from sourceViewModel...
              
            //add to destinationViewModel...
        }
    }

    The OnDropInfo only gets called once, for the tree onto which is dropped, even though the source tree is subscribed to the same event using the same event handler.

    What I don't like about the solution, is that into the OnDropInfo I don't have access to the drop position, and I have to "share" the EventArgs of the PreviewDragEnded.

    Feels like a hack, but do you have any better ideas on how to access the DropPosition in the OnDropInfo event?
    If not, do you see any scenarios which this solution doesn't cover?
  3. DevCraft banner
  4. Petar Mladenov
    Admin
    Petar Mladenov avatar
    2891 posts

    Posted 26 Jul 2011 Link to this post

    Hi Christian Burkhardt,

     The RadTreeViewItem exposes DropPosition property. So you can do like so in the DropInfo:

    DropPosition dropPos = (e.Options.Destination as RadTreeViewItem).DropPosition;
    Please let us know if this works for you.Regards,
    Petar Mladenov
    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!

  5. James
    James avatar
    117 posts
    Member since:
    Mar 2009

    Posted 01 Aug 2011 Link to this post

    Hi Petar,

    I've tracked this thread, as I have the same challenge. Is using the drag-drop manager the only way of doing this? (i.e. there is no way of knowing in PreviewDragEnded which tree you are dealing with (when the TargetDropItem is null)?

    Thanks, James.
  6. James
    James avatar
    117 posts
    Member since:
    Mar 2009

    Posted 02 Aug 2011 Link to this post

    Sorry - please ignore that question. Of course, when reordering the TargetDropItem can't be null...!

    James.
  7. Christian Burkhardt
    Christian Burkhardt avatar
    23 posts
    Member since:
    Feb 2010

    Posted 04 Aug 2011 Link to this post

    Hi Telerik,
    Yes this works, thank you for the solution.
Back to Top
DevCraft banner