Problems with DragDropManager on TreeView

4 posts, 0 answers
  1. Alexander
    Alexander avatar
    77 posts
    Member since:
    Apr 2013

    Posted 15 Jul 2014 Link to this post

    Hello,

    I'm trying to implement some Drag and Drop functionality on an inhomogenious RadTreeView. I started from the "Tree to Grid Drag" Demo project.
    There you define some DropIndicationDetails to display the input location. However I don't like this style (and the fact that I have to create a datatemplate for drag and drop) - which is why I want to use the default drag/drop appearance with the Windows 8 style (see attached image).

    I therefore created a simplified version of the TreeViewDragDopBehavior:

    public class TreeViewDragDropBehavior
    {
        public static bool GetIsEnabled(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsEnabledProperty);
        }
     
        public static void SetIsEnabled(DependencyObject obj, bool value)
        {
            obj.SetValue(IsEnabledProperty, value);
        }
     
        public static readonly DependencyProperty IsEnabledProperty =
            DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(TreeViewDragDropBehavior),
                new PropertyMetadata(OnIsEnabledPropertyChanged));
     
        public static void OnIsEnabledPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            if (true.Equals(e.NewValue))
            {
                Initialize(dependencyObject as RadTreeView);
            }
            else
            {
                CleanUp(dependencyObject as RadTreeView);
            }
        }
     
        protected static void Initialize(RadTreeView treeView)
        {
            DragDropManager.AddDragInitializeHandler(treeView, OnDragInitialize, true);
            DragDropManager.AddGiveFeedbackHandler(treeView, OnGiveFeedback, true);
            DragDropManager.AddDragDropCompletedHandler(treeView, OnDragDropCompleted, true);
            DragDropManager.AddDropHandler(treeView, OnDrop, true);
     
            treeView.ItemPrepared += AssociatedObject_ItemPrepared;
        }
     
        protected static void CleanUp(RadTreeView treeView)
        {
            DragDropManager.RemoveDragInitializeHandler(treeView, OnDragInitialize);
            DragDropManager.RemoveGiveFeedbackHandler(treeView, OnGiveFeedback);
            DragDropManager.RemoveDragDropCompletedHandler(treeView, OnDragDropCompleted);
            DragDropManager.RemoveDropHandler(treeView, OnDrop);
        }
     
        static void AssociatedObject_ItemPrepared(object sender, RadTreeViewItemPreparedEventArgs e)
        {
            DragDropManager.RemoveDragOverHandler(e.PreparedItem, OnItemDragOver);
            DragDropManager.AddDragOverHandler(e.PreparedItem, OnItemDragOver);
        }
     
        private static void OnDragInitialize(object sender, DragInitializeEventArgs e)
        {
            var treeViewItem = e.OriginalSource as RadTreeViewItem ?? (e.OriginalSource as FrameworkElement).ParentOfType<RadTreeViewItem>();
            var data = treeViewItem != null ? treeViewItem.Item : (sender as RadTreeView).SelectedItem;
     
            var payload = DragDropPayloadManager.GeneratePayload(null);
            payload.SetData("DraggedData", data);
     
            e.Data = payload;
            e.DragVisualOffset = e.RelativeStartPoint;
            e.AllowedEffects = DragDropEffects.All;
        }
     
        private static void OnGiveFeedback(object sender, Telerik.Windows.DragDrop.GiveFeedbackEventArgs e)
        {
            e.SetCursor(Cursors.Arrow);
            e.Handled = true;
        }
     
        private static void OnDragDropCompleted(object sender, DragDropCompletedEventArgs e)
        {
            e.Handled = true;
        }
     
        private static void OnDrop(object sender, Telerik.Windows.DragDrop.DragEventArgs e)
        {
        }
     
        private static void OnItemDragOver(object sender, Telerik.Windows.DragDrop.DragEventArgs e)
        {
            e.Effects = DragDropEffects.All;
            e.Handled = true;
        }
    }

    However, although I set 'e.Effects = DragDropEffects.All' in the OnItemDragOver method, it always shows the forbidden icon (in the OnDrop method, the Effects are correct). If I do not set the payload (by simply commenting out this line in the OnDragInitialize method), I get the expected appearance as in the screen shot. However - the OnItemDragOver method is never called. Therefore, I don't have any possibility to manually override the e.Effects settings.

    Is there any way to influence the effects if I dont set the payload manually? Or alternatively to show the correect drop position without having handle it manually?

    By the way - there is a very severy memory leak in your original example! You store the TreeViewDragDropBehavior in a static dictionary, together with the RadTreeView. This keeps the TreeViewDragDropBehavior, its associated RadTreeView, it's TreeViewItems and the corresponding data alive forever.

    Alexander Müller
  2. Petar Mladenov
    Admin
    Petar Mladenov avatar
    2891 posts

    Posted 16 Jul 2014 Link to this post

    Hi Alexander,

    The example you use as a base is a bit old and we encourage you to use the built in DragDrop of the RadTreeView. You can use TreeView's DragDrop sample in our Demos and the following support resources:
    RadTreeView DragDrop overview
    RadTreeView DragDrop How Tos - Drag Between 2 TreeViews
    It is in our plans to update / refactor this sample to not use TreeViewDragDropBehavior but only the DragDropManager events - this would minimize the code of the sample. With this refactoring we will also remove the mentioned memory leaks.

    Please let us know if the provided resources move you in the right direction.

    Regards,
    Petar Mladenov
    Telerik
     
    Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
     
  3. UI for WPF is Visual Studio 2017 Ready
  4. Alexander
    Alexander avatar
    77 posts
    Member since:
    Apr 2013

    Posted 16 Jul 2014 in reply to Petar Mladenov Link to this post

    Thanks for the info.

    I was missing the TreeViewDragDropOptions. By calling setting the DropAction and calling UpdateDragVisual(), I managed to show the correct drag sign. However, setting the DropPosition does not seem to have an effect? I expected that the DropPreviewLine would update/hide accordingly.

    Just a note: It would be nice to have some information which sample are up-to-date. You suggest to use the built-in DragDrop of the RadTreeView, but the "RadTreeView DragDrop overview" linked by you uses some deprecated events like PreviewDragStarted...

    Alexander Müller
  5. Petar Mladenov
    Admin
    Petar Mladenov avatar
    2891 posts

    Posted 18 Jul 2014 Link to this post

    Hello Alexander,

    You can try invoking the UpdatedDropPreviewLine method of the RadTreeView. If this does not help, you can isolate your issue in a sample project, send it in a new support thread and we will be better able to investigate it and advice you accordingly.

    I believe in the mentioned article there are Important Notes on every place where a Legacy code is used.
    Also there are notes prompting the users to use only the New mode.
     Please let us know if we have missed something to note in the article and we will update it.

    Regards,
    Petar Mladenov
    Telerik
     
    Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
     
Back to Top