8 Answers, 1 is accepted
You can use the QueryContinueDrag and the DragLeave event to achieve the functionality you require. You can read more about the events here.
Hope this helps!
Nik
the Telerik team
Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>
DragLeave is only fired when I'm moving ListViewItems to the right; when moving left out of the ListView DragLeave is not fired.
With QueryContinueDrag I can cancel the drag operation by setting e.Action = DragAction.Cancel. However, this cancels the complete operation. All I want to achieve is to limit the drop target to one specific ListView.
Thanks,
Michael
If you don't want to cancel the drag completely, you may use the drag leave event to set the allowed effects of the drag drop operation.
DragLeave is only fired when I'm moving ListViewItems to the right; when moving left out of the ListView DragLeave is not fired.
Could you provide an example of this issue, since this is something we have not encountered so far?
Thank you in advance!
Nik
the Telerik team
Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>
I've tried to create a simple example, but I couldn't reproduce the behaviour. Instead I get two other problerms: "DragLeave" is now fired as soon as I move a ListViewItem, no mattter whether the dragged item has left the ListView or not. And if I'm setting the Effect to DragDropEffects.None nothing changes, I can still drop the item out of the ListView.
Here's my code:
.xaml:
<
Window
x:Class
=
"DragTest.MainWindow"
xmlns:telerik
=
"http://schemas.telerik.com/2008/xaml/presentation"
Title
=
"MainWindow"
Height
=
"350"
Width
=
"525"
>
<
Window.Resources
>
<
Style
TargetType
=
"ListViewItem"
x:Key
=
"IndexItemStyle"
>
<
Setter
Property
=
"telerik:DragDropManager.AllowCapturedDrag"
Value
=
"True"
/>
</
Style
>
</
Window.Resources
>
<
DockPanel
>
<
telerik:RadTreeView
DockPanel.Dock
=
"Left"
Width
=
"200"
BorderThickness
=
"1"
BorderBrush
=
"Gray"
/>
<
TextBox
DockPanel.Dock
=
"Right"
Width
=
"100"
BorderThickness
=
"1"
/>
<
ListView
Name
=
"listView"
ItemContainerStyle
=
"{StaticResource IndexItemStyle}"
Margin
=
"20"
>
<
ListView.View
>
<
GridView
>
<
GridViewColumn
Width
=
"120"
Header
=
"Name"
DisplayMemberBinding
=
"{Binding}"
/>
</
GridView
>
</
ListView.View
>
<
telerik:ListBoxDragDrop.Behavior
>
<
telerik:ListBoxDragDropBehavior
/>
</
telerik:ListBoxDragDrop.Behavior
>
<
telerik:ListBoxDragDrop.DragVisualProvider
>
<
telerik:ScreenshotDragVisualProvider
/>
</
telerik:ListBoxDragDrop.DragVisualProvider
>
</
ListView
>
</
DockPanel
>
</
Window
>
.cs:
using
System;
using
System.Collections.ObjectModel;
using
System.Diagnostics;
using
System.Windows;
using
Telerik.Windows.DragDrop;
namespace
DragTest
{
public
partial
class
MainWindow : Window
{
public
MainWindow()
{
InitializeComponent();
listView.ItemsSource =
new
ObservableCollection<
string
>() {
"aaa"
,
"bbb"
,
"ccc"
};
DragDropManager.AddDragLeaveHandler(listView, OnDragLeave);
}
private
void
OnDragLeave(
object
sender, Telerik.Windows.DragDrop.DragEventArgs args)
{
Trace.WriteLine(
"OnDragLeave"
);
args.Effects = DragDropEffects.None;
args.Handled =
true
;
}
}
}
Regards,
Michael
It seems that there is an issue in the RadTreeView, since the only place you can drop besides the ListView is the TreeView. I managed to solve the issue by adding a DragOver handler to the tree view and setting the drag effects there.
Other than that when using drag drop behaviors adding AllowDrop = false to the controls you don't want to be able to drop to is usually sufficient for achieving similar behavior. If you have to use more custom logic in order to determine whether you a control is a valid drop target you can create a custom DragDropBehavior, much like the one I have implemented in the test project I used.
I am attaching the Solution I used to show the exact approach.
Hope it helps!
Nik
the Telerik team
Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>
thanks, adding a DragOver-Handler to the treeview solved my problem.
Regards,
Michael
What I did was very similar to the posted solution with this addition:
within your ListBoxDragDropBehavior class:
public MyListBoxDragDropBehavior:ListBoxDragDropBehavior
{
...(the rest of the example's code)...
public override void Drop(DragDropState state)
{
base.Drop(state);
}
public override void DragDropCanceled(DragDropState state)
{
base.DragDropCanceled(state);
GCDragDropState newState = new CanceledDragDropState(state);
Drop(newState);
}
}
With the CanceledDragDropState class looking like:
-----------------------------------------------------------------------------------
public class CanceledDragDropState : DragDropState
{
public CanceledDragDropState(DragDropState state)
{
DestinationItemsSource = state.SourceItemsSource;
SourceItemsSource = state.SourceItemsSource;
this.InsertIndex = state.InsertIndex;
this.IsControlDown = state.IsControlDown;
this.IsShiftDown = state.IsShiftDown;
this.DraggedItems = state.DraggedItems;
this.DropPosition = state.DropPosition;
}
public CanceledDragDropState()
{
}
}
-----------------------------------------------------------------------------------
What this does is invokes the DragDropManager to "re-insert" the item in question back into your observable list, which if you attach to the CollectionChanged event handler and put a break point in there you will see, after the Drop call is made from within the DragDropCanceled method, the CollectionChanged event fire twice:
First time: it removes the item from the list that was being dragged.
Second time: it puts the same item back into the list...
Not exactly sure why this was the only way I could make this work with a "non-datatemplated" drag and drop scenario, but it seems to do the trick.
Anyway, if someone at Telerik reads this and thinks it a horrid solution, then if you wouldn't mind posting a solution to the issue where if you don't define a DataTemplate for your listbox items then if you have a canceled drag drop event occur the content of the listbox item "vanishes"... unless you select the thin listbox item shell and drag and drop it onto the same listbox it originated from
=or=
you apply the above solution to the ListBoxDragDropBehavior and attach that behavior to your listboxes as is shown by the example provided by Nick.
Basically the base implementation of DragDropCompleted method remove the item from the source ItemsSource. In order to avoid that you would need to avoid that call to the base method.
I can suggest you two solutions depending on the number of the ListBoxes you are using. For example if you are using only single ListBox - you can simply call the base DragDropCompleted() method only whenever the item is dropped on the same control:
public
override
void
DragDropCompleted(DragDropState state)
{
if
(state.IsSameControl)
{
base
.DragDropCompleted(state);
}
}
If you are using multiple ListBoxes with the same custom ListBoxDragDropBehavior attached - you can use a custom static bool flag indicating whether the item is dropped in one of the ListBoxes. The Drop method will be called from the behavior of the destination ListBox and DragDropCompleted will be called from the source ListBox. This way you would be able to remove the item only when the Drop was performed on one of the ListBoxes:
public
class
CustomListBoxDragDropBehavior : ListBoxDragDropBehavior
{
private
static
bool
droppedInsideListBox;
public
override
void
Drop(DragDropState state)
{
droppedInsideListBox =
true
;
base
.Drop(state);
}
public
override
void
DragDropCompleted(DragDropState state)
{
if
(droppedInsideListBox)
{
droppedInsideListBox =
false
;
base
.DragDropCompleted(state);
}
}
}
Hope this helps.
Regards,
Kalin
Telerik
Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.