How to get chosen effect on DragDropCompleted

3 posts, 0 answers
  1. Roland
    Roland avatar
    4 posts
    Member since:
    Aug 2017

    Posted 10 Aug Link to this post

    I have a treeview and a gridview. The user should be able to move elements from the gridview to the treeview and change the effect of the drag&drop action by using the shift or control key (like in Windows Explorer).

    In the GiveFeedback event the effect is set according to the pressed key and also the visualization shows the expected behavior. But in the Drop event (on the treeview) and in the DragDropCompleted event (on the gridview) the effect is set to All, therefore I'm not able to decide if I have to remove the Element from the current list.

    Am I missing something or is there a Bug in the library?

     

    XAML:

    <Window x:Class="DragAndDropToTreeView.MainWindow"
            xmlns:local="clr-namespace:DragAndDropToTreeView"
            Title="MainWindow"
            Width="623"
            Height="461">
      <Grid>
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="1*" />
          <ColumnDefinition Width="2*" />
        </Grid.ColumnDefinitions>
        <telerik:RadTreeView AllowDrop="True"
                             ItemsSource="{Binding Folders}"
                             SelectedItem="{Binding SelectedFolder,
                                                    Mode=TwoWay}"
                             SelectionMode="Single">
          <telerik:RadTreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type local:Folder}" ItemsSource="{Binding Children}">
              <Grid VerticalAlignment="Center">
                <TextBlock VerticalAlignment="Center"
                           Text="{Binding Name}"
                           local:TreeItemDropBehavior.IsEnabled="True" />
              </Grid>
            </HierarchicalDataTemplate>
          </telerik:RadTreeView.Resources>
        </telerik:RadTreeView>
        <telerik:RadGridView Grid.Column="1"
                             AllowDrop="True"
                             AutoGenerateColumns="False"
                             CanUserFreezeColumns="False"
                             CanUserReorderColumns="False"
                             CanUserResizeColumns="False"
                             FontSize="12"
                             IsFilteringAllowed="False"
                             IsReadOnly="True"
                             ItemsSource="{Binding SelectedFolder.Elements}"
                             RowHeight="32"
                             RowIndicatorVisibility="Collapsed"
                             SelectionMode="Multiple"
                             ShowGroupPanel="False"
                             local:GridViewDragDropBehavior.IsEnabled="True"
                             telerik:DragDropManager.AllowCapturedDrag="True"
                             telerik:DragDropManager.AllowDrag="True">
          <telerik:RadGridView.Resources>
            <ResourceDictionary>
              <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary>
                  <DataTemplate x:Key="DraggedItemTemplate">
                    <StackPanel Orientation="Horizontal">
                      <TextBlock Text="Dragging: " />
                      <TextBlock FontWeight="Bold" Text="{Binding CurrentDraggedItems.Count}" />
                      <TextBlock Text=" Element(s)" />
                    </StackPanel>
                  </DataTemplate>
                </ResourceDictionary>
              </ResourceDictionary.MergedDictionaries>
            </ResourceDictionary>
          </telerik:RadGridView.Resources>
          <telerik:RadGridView.Columns>
            <telerik:GridViewDataColumn Width="100"
                                        DataMemberBinding="{Binding Name}"
                                        Header="Name" />
            <telerik:GridViewDataColumn Width="250"
                                        DataMemberBinding="{Binding Description}"
                                        Header="Description" />
          </telerik:RadGridView.Columns>
        </telerik:RadGridView>
      </Grid>
    </Window>

     

    GridViewDragDropBehavior.cs:

    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Windows;
    using System.Windows.Input;
     
    using Telerik.Windows.Controls;
    using Telerik.Windows.DragDrop;
    using Telerik.Windows.DragDrop.Behaviors;
     
    using GiveFeedbackEventArgs = Telerik.Windows.DragDrop.GiveFeedbackEventArgs;
     
    namespace DragAndDropToTreeView
    {
      public class GridViewDragDropBehavior
      {
        public RadGridView AssociatedControl { get; set; }
     
        private static readonly Dictionary<RadGridView, GridViewDragDropBehavior> Instances;
     
        static GridViewDragDropBehavior()
        {
          Instances = new Dictionary<RadGridView, GridViewDragDropBehavior>();
        }
     
        public static bool GetIsEnabled(DependencyObject obj)
        {
          return (bool)obj.GetValue(IsEnabledProperty);
        }
     
        public static void SetIsEnabled(DependencyObject obj, bool value)
        {
          GridViewDragDropBehavior behavior = GetAttachedBehavior(obj as RadGridView);
     
          behavior.AssociatedControl = obj as RadGridView;
     
          if (value)
          {
            behavior.Initialize();
          }
          else
          {
            behavior.CleanUp();
          }
     
          obj.SetValue(IsEnabledProperty, value);
        }
     
        public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.RegisterAttached(
          "IsEnabled",
          typeof(bool),
          typeof(GridViewDragDropBehavior),
          new PropertyMetadata(OnIsEnabledPropertyChanged));
     
        public static void OnIsEnabledPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
          SetIsEnabled(dependencyObject, (bool)e.NewValue);
        }
     
        private static GridViewDragDropBehavior GetAttachedBehavior(RadGridView gridView)
        {
          if (!Instances.ContainsKey(gridView))
          {
            Instances[gridView] = new GridViewDragDropBehavior { AssociatedControl = gridView };
          }
     
          return Instances[gridView];
        }
     
        protected virtual void Initialize()
        {
          UnsubscribeFromDragDropEvents();
          SubscribeToDragDropEvents();
        }
     
        protected virtual void CleanUp()
        {
          UnsubscribeFromDragDropEvents();
        }
     
        private void SubscribeToDragDropEvents()
        {
          DragDropManager.AddDragInitializeHandler(AssociatedControl, OnDragInitialize);
          DragDropManager.AddGiveFeedbackHandler(AssociatedControl, OnGiveFeedback);
          DragDropManager.AddDragDropCompletedHandler(AssociatedControl, OnDragDropCompleted);
          DragDropManager.AddDragOverHandler(AssociatedControl, OnDragOver);
        }
     
        private void UnsubscribeFromDragDropEvents()
        {
          DragDropManager.RemoveDragInitializeHandler(AssociatedControl, OnDragInitialize);
          DragDropManager.RemoveGiveFeedbackHandler(AssociatedControl, OnGiveFeedback);
          DragDropManager.RemoveDragDropCompletedHandler(AssociatedControl, OnDragDropCompleted);
          DragDropManager.RemoveDragOverHandler(AssociatedControl, OnDragOver);
        }
     
        private void OnDragInitialize(object sender, DragInitializeEventArgs e)
        {
          DropIndicationDetails details = new DropIndicationDetails();
          var gridView = sender as RadGridView;
          details.DragSource = gridView.ItemsSource;
     
          var items = gridView.SelectedItems;
          details.CurrentDraggedItems = items;
     
          IDragPayload dragPayload = DragDropPayloadManager.GeneratePayload(null);
     
          dragPayload.SetData("DraggedData", items);
          dragPayload.SetData("DropDetails", details);
     
          e.Data = dragPayload;
     
          e.DragVisual = new DragVisual { Content = details, ContentTemplate = AssociatedControl.Resources["DraggedItemTemplate"] as DataTemplate };
          e.DragVisualOffset = new Point(e.RelativeStartPoint.X + 10, e.RelativeStartPoint.Y);
          e.AllowedEffects = DragDropEffects.All;
        }
     
        private void OnGiveFeedback(object sender, GiveFeedbackEventArgs e)
        {
          Debug.WriteLine("GridViewDragDropBehavior.OnGiveFeedback {0}", e.Effects);
          e.SetCursor(Cursors.Arrow);
          e.Handled = true;
        }
     
        private void OnDragDropCompleted(object sender, DragDropCompletedEventArgs e)
        {
          Debug.WriteLine("GridViewDragDropBehavior.OnDragDropCompleted: {0}", e.Effects);
          var data = DragDropPayloadManager.GetDataFromObject(e.Data, "DraggedData") as IList;
          var details = DragDropPayloadManager.GetDataFromObject(e.Data, "DropDetails");
          Debug.WriteLine(e.Effects);
     
          // Remove Element from source list if drag drop effect is move
          /*if (e.Effects == DragDropEffects.Move)
          {
            var collection = (details as DropIndicationDetails).DragSource as IList;
            foreach(var element in data)
            {
              collection.Remove(element);
            }
          }*/
        }
     
        private void OnDragOver(object sender, Telerik.Windows.DragDrop.DragEventArgs e)
        {
          Debug.WriteLine("GridViewDragDropBehavior.OnDragOver: {0}", e.Effects);
          e.Effects = DragDropEffects.None;
          e.Handled = true;
        }
      }
    }

     

    TreeItemDropBehavior.cs:

    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Windows;
    using System.Windows.Input;
    using Telerik.Windows.Controls;
    using Telerik.Windows.DragDrop;
     
    namespace DragAndDropToTreeView
    {
      public class TreeItemDropBehavior
      {
        /// <summary>
        /// AssociatedObject Property
        /// </summary>
        public RadTreeViewItem AssociatedObject { get; set; }
     
        private static readonly Dictionary<RadTreeViewItem, TreeItemDropBehavior> Instances;
     
        static TreeItemDropBehavior()
        {
          Instances = new Dictionary<RadTreeViewItem, TreeItemDropBehavior>();
        }
     
        public static bool GetIsEnabled(DependencyObject obj)
        {
          return (bool)obj.GetValue(IsEnabledProperty);
        }
     
        public static void SetIsEnabled(DependencyObject obj, bool value)
        {
          var treeViewItem = obj.ParentOfType<RadTreeViewItem>();
          TreeItemDropBehavior behavior = GetAttachedBehavior(treeViewItem);
     
          behavior.AssociatedObject = treeViewItem;
     
          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(TreeItemDropBehavior),
          new PropertyMetadata(OnIsEnabledPropertyChanged));
     
        public static void OnIsEnabledPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
          SetIsEnabled(dependencyObject, (bool)e.NewValue);
        }
     
        private static TreeItemDropBehavior GetAttachedBehavior(RadTreeViewItem treeViewItem)
        {
          if (!Instances.ContainsKey(treeViewItem))
          {
            Instances[treeViewItem] = new TreeItemDropBehavior { AssociatedObject = treeViewItem };
          }
     
          return Instances[treeViewItem];
        }
     
        protected virtual void Initialize()
        {
          DragDropManager.AddGiveFeedbackHandler(AssociatedObject, OnGiveFeedback);
          DragDropManager.AddDropHandler(AssociatedObject, OnDrop);
        }
     
        protected virtual void CleanUp()
        {
          DragDropManager.RemoveGiveFeedbackHandler(AssociatedObject, OnGiveFeedback);
          DragDropManager.RemoveDropHandler(AssociatedObject, OnDrop);
        }
     
        private void OnGiveFeedback(object sender, Telerik.Windows.DragDrop.GiveFeedbackEventArgs e)
        {
          Debug.WriteLine("TreeItemDropBehavior.OnGiveFeedback {0}", e.Effects);
          e.SetCursor(Cursors.Arrow);
          e.Handled = true;
        }
     
        private void OnDrop(object sender, Telerik.Windows.DragDrop.DragEventArgs e)
        {
          Debug.WriteLine("TreeItemDropBehavior.OnDrop: {0}", e.Effects);
     
          if (e.Effects != DragDropEffects.None)
          {
            var destinationItem = (e.OriginalSource as FrameworkElement).ParentOfType<RadTreeViewItem>();
            var data = DragDropPayloadManager.GetDataFromObject(e.Data, "DraggedData") as IList;
            var details = DragDropPayloadManager.GetDataFromObject(e.Data, "DropDetails") as DropIndicationDetails;
     
            if (destinationItem != null)
            {
              foreach (var element in data)
              {
                (destinationItem.DataContext as Folder).Elements.Add(element as Element);
              }
     
              e.Handled = true;
            }
          }
        }
      }
    }
  2. Roland
    Roland avatar
    4 posts
    Member since:
    Aug 2017

    Posted 10 Aug in reply to Roland Link to this post

    Complete example project can be found here:

    https://github.com/rolandbaer/DragAndDropToTreeView

  3. Martin Ivanov
    Admin
    Martin Ivanov avatar
    1408 posts

    Posted 15 Aug Link to this post

    Hello Roland,

    I tested your project and indeed, the drag/drop effects in the treeview's Drop event handler are different then the one set in the gridview's DragOver. This happens because the allowed effects are associated with the current element that executes the drag/drop event. 

    In your case, the effects are set in the DragOver of the gridview. This means that those effects are valid in the gridview context. However, when you reach the treeview, the effects will be updated to match the new context.

    In order to achieve your requirement you can update the allowed effects also in the DragOver of the treeview control. Or you can set the allowed effects only in the DragInitialize event of the gridview. 

    Regards,
    Martin Ivanov
    Progress Telerik
    Want to extend the target reach of your WPF applications, leveraging iOS, Android, and UWP? Try UI for Xamarin, a suite of polished and feature-rich components for the Xamarin framework, which allow you to write beautiful native mobile apps using a single shared C# codebase.
Back to Top