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

TreeListView DragDrop Visuals and Tooltip

4 Answers 179 Views
TreeListView
This is a migrated thread and some comments may be shown as answers.
Ryan
Top achievements
Rank 1
Ryan asked on 10 Aug 2016, 03:50 PM
Hello,

While comparing TreeView and TreeListView controls, I've found that the out-of-the-box visuals for DragDrop is much more complete for the TreeView than it is for the TreeListView. I've attached two images, the first showing the TreeView's preview, and the second is showing the TreeListView.

I could not find any examples of the TreeListView that would give a preview like "Drop before x..", can this be achieved for the TreeListView? 

Thanks, 
Ryan

4 Answers, 1 is accepted

Sort by
0
Yoan
Telerik team
answered on 15 Aug 2016, 12:42 PM
Hi Ryan,

It seems that the attachments are missing. However, custom dropIndication details can be achieved with RadTreeListView control. You can check this online demo which demonstrates how this is achieved for the TreeView (please check the TreeViewDragDropBehavior class). The same approach is applicable with little modifications for the TreeListView.

Regards,
Yoan
Telerik by Progress
Do you need help with upgrading your AJAX, WPF or WinForms project? Check the Telerik API Analyzer and share your thoughts.
0
Ryan
Top achievements
Rank 1
answered on 15 Aug 2016, 07:19 PM
Thanks for the references. Too bad there is not anything specific for the TreeListView. Is the drag and drop behavior for the TreeListView more closely related to the GridView, or the TreeView? 

Using the behavior below, what pieces are missing for displaying the "drop before", "drop inside" tooltips? 

Thanks,
Ryan

public class TreeViewDragDropBehavior
    {
        private object originalSource = null;
        private IList sourceCollection = null;
        private IList destinationCollection = null;
 
        private RadTreeListView _associatedObject;
         
        public IList SourceCollection
        {
            get
            {
                return this.sourceCollection;
            }
            set
            {
                this.sourceCollection = value;
            }
        }
 
        /// <summary>
        /// AssociatedObject Property
        /// </summary>
        public RadTreeListView AssociatedObject
        {
            get
            {
                return _associatedObject;
            }
            set
            {
                _associatedObject = value;
            }
        }
 
        private static Dictionary<RadTreeListView, TreeViewDragDropBehavior> instances;
 
        static TreeViewDragDropBehavior()
        {
            instances = new Dictionary<RadTreeListView, TreeViewDragDropBehavior>();
        }
 
        public static bool GetIsEnabled(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsEnabledProperty);
        }
 
        public static void SetIsEnabled(DependencyObject obj, bool value)
        {
            TreeViewDragDropBehavior behavior = GetAttachedBehavior(obj as RadTreeListView);
 
            behavior.AssociatedObject = obj as RadTreeListView;
 
            if (value)
            {
                behavior.Initialize();
            }
            else
            {
                behavior.CleanUp();
            }
            obj.SetValue(IsEnabledProperty, value);
        }
 
        // Using a DependencyProperty as the backing store for IsEnabled.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsEnabledProperty =
            DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(TreeViewDragDropBehavior),
                new PropertyMetadata(new PropertyChangedCallback(OnIsEnabledPropertyChanged)));
 
        public static void OnIsEnabledPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            #if !SILVERLIGHT
            SetIsEnabled(dependencyObject, (bool)e.NewValue);
            #endif
        }
 
        public static TreeViewDragDropBehavior GetAttachedBehavior(RadTreeListView gridview)
        {
            if (!instances.ContainsKey(gridview))
            {
                instances[gridview] = new TreeViewDragDropBehavior();
                instances[gridview].AssociatedObject = gridview;
            }
 
            return instances[gridview];
        }
 
        protected virtual void Initialize()
        {
            DragDropManager.AddDragInitializeHandler(this.AssociatedObject, OnDragInitialize, true);
            DragDropManager.AddDropHandler(this.AssociatedObject, OnDrop, true);
            DragDropManager.AddDragDropCompletedHandler(this.AssociatedObject, OnDragDropCompleted, true);
            DragDropManager.AddDragOverHandler(this.AssociatedObject, OnDragOver, true);
 
            this.AssociatedObject.DataLoaded += RadTreeListView1_DataLoaded;
        }
 
        protected virtual void CleanUp()
        {
            DragDropManager.RemoveDragInitializeHandler(this.AssociatedObject, OnDragInitialize);
            DragDropManager.RemoveDropHandler(this.AssociatedObject, OnDrop);
            DragDropManager.RemoveDragDropCompletedHandler(this.AssociatedObject, OnDragDropCompleted);
            DragDropManager.RemoveDragOverHandler(this.AssociatedObject, OnDragOver);
 
            this.AssociatedObject.DataLoaded -= RadTreeListView1_DataLoaded;
        }
 
        private void OnDragInitialize(object sender, DragInitializeEventArgs e)
        {
            var sourceRow = (e.OriginalSource as TreeListViewRow) ?? (e.OriginalSource as FrameworkElement).ParentOfType<TreeListViewRow>();
 
            if (sourceRow != null)
            {
                var dataObject = DragDropPayloadManager.GeneratePayload(null);
 
                var draggedItem = sourceRow.Item;
 
                DragDropPayloadManager.SetData(dataObject, "DragData", new Collection<object>() { draggedItem });
                e.Data = dataObject;
 
                var screenshotVisualProvider = new ScreenshotDragVisualProvider();
                e.DragVisual = screenshotVisualProvider.CreateDragVisual(new DragVisualProviderState(e.RelativeStartPoint, new List<object>() { draggedItem }, new List<DependencyObject>() { sourceRow }, sender as FrameworkElement));
                e.DragVisualOffset = new Point(0, 0);
                this.originalSource = sourceRow.Item;
                this.sourceCollection = sourceRow.ParentRow != null ? (IList)sourceRow.ParentRow.Items.SourceCollection : (IList)sourceRow.GridViewDataControl.ItemsSource;
            }
        }
 
        private void OnDragDropCompleted(object sender, DragDropCompletedEventArgs e)
        {
        }
 
        private void OnDrop(object sender, Telerik.Windows.DragDrop.DragEventArgs e)
        {
            if (e.Data != null && e.AllowedEffects != DragDropEffects.None)
            {
                Collection<Object> payload = DragDropPayloadManager.GetDataFromObject(e.Data, "DragData") as Collection<Object>;
                if (payload != null)
                {
                    Folder droppedItem = (Folder)payload[0];
                    var destinationRow = e.OriginalSource as TreeListViewRow ?? (e.OriginalSource as FrameworkElement).ParentOfType<TreeListViewRow>();
                    if (destinationRow != null)
                    {
                        Folder targetItem = destinationRow.DataContext as Folder;
                        TreeListViewDropPosition relativeDropPosition = (TreeListViewDropPosition)destinationRow.GetValue(RadTreeListView.DropPositionProperty);
                        this.destinationCollection = relativeDropPosition == TreeListViewDropPosition.Inside ? (IList)destinationRow.Items.SourceCollection :
                                                                                                                                                             destinationRow.ParentRow != null ? (IList)destinationRow.ParentRow.Items.SourceCollection : (IList)destinationRow.GridViewDataControl.ItemsSource;
                        MoveItem(droppedItem, targetItem, relativeDropPosition);
                    }
                    else
                    {
                        this.destinationCollection = (IList)(sender as RadTreeListView).ItemsSource;
                        MoveItemToRoot(droppedItem);
                    }
                }
            }
        }
 
        private void OnDragOver(object sender, Telerik.Windows.DragDrop.DragEventArgs e)
        {
            var dropTarget = e.OriginalSource as TreeListViewRow ?? (e.OriginalSource as FrameworkElement).ParentOfType<TreeListViewRow>();
            if (this.IsChildOf(dropTarget, this.originalSource))
            {
                e.Effects = DragDropEffects.None;
            }
 
            e.Handled = true;
        }
 
        private bool IsChildOf(TreeListViewRow dropTarget, object originalSource)
        {
            var currentElement = dropTarget;
            while (currentElement != null)
            {
                if (currentElement.Item == originalSource)
                {
                    return true;
                }
 
                currentElement = currentElement.ParentRow;
            }
 
            return false;
        }
 
        void RadTreeListView1_DataLoaded(object sender, EventArgs e)
        {
            this.AssociatedObject.DataLoaded -= new EventHandler<EventArgs>(RadTreeListView1_DataLoaded);
            this.AssociatedObject.ExpandAllHierarchyItems();
        }
 
        private void MoveItemToRoot(Folder droppedItem)
        {
            var parentCollection = sourceCollection;
            parentCollection.Remove(droppedItem);
            droppedItem.ParentFolder = null;
            (destinationCollection).Add(droppedItem);
 
            this.AssociatedObject.ExpandAllHierarchyItems();
        }
 
        private void MoveItem(Folder droppedItem, Folder targetItem, TreeListViewDropPosition relativeDropPosition)
        {
            if (droppedItem == targetItem)
                return;
 
            var parentCollection = this.sourceCollection;
 
            parentCollection.Remove(droppedItem);
 
            if (relativeDropPosition == TreeListViewDropPosition.Inside)
            {
                destinationCollection.Add(droppedItem);
            }
            else if (relativeDropPosition == TreeListViewDropPosition.Before)
            {
                destinationCollection.Insert(destinationCollection.IndexOf(targetItem), droppedItem);
            }
            else if (relativeDropPosition == TreeListViewDropPosition.After)
            {
                destinationCollection.Insert(destinationCollection.IndexOf(targetItem) + 1, droppedItem);
            }
 
            this.AssociatedObject.ExpandAllHierarchyItems();
        }
    }
0
Ryan
Top achievements
Rank 1
answered on 17 Aug 2016, 08:07 PM
So I figured out something that somewhat emulates the TreeView's DragDrop behavior. I'm using a DragDrop template, which has a ContentPresenter that takes in the screenshot object from the ScreenshotDragVisualProvider().CreateDragVisual(). So I have a preview screenshot of all the nodes being moved, and a preview screenshot of the target node, and I just use the custom template to display the drop position w/the ContentPresenters which show the screenshot visuals. 

Thanks for the help,
Ryan
0
Stefan
Telerik team
answered on 18 Aug 2016, 03:20 PM
Hello Ryan,

We already discussed this in the support thread you opened regarding this topic. I will, however, paste my answer here as well, so that it is shared with the community.

In order to customize the appearance of the dragged item, you need to set the DragVisual property of the event arguments of the DragInitialize event handler. It provides the Content and ContentTemplate properties, which you can use to achieve the desired appearance.

Please take a look at the Drag and Drop within RadGridView help topic and the relevant SDK Example, as the approach demonstrated there is applicable to RadTreeListView as well.


All the best,
Stefan X1
Telerik by Progress
Do you need help with upgrading your AJAX, WPF or WinForms project? Check the Telerik API Analyzer and share your thoughts.
Tags
TreeListView
Asked by
Ryan
Top achievements
Rank 1
Answers by
Yoan
Telerik team
Ryan
Top achievements
Rank 1
Stefan
Telerik team
Share this question
or