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" xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" 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; } } } }}