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

Prevent drop if outside destination

8 Answers 944 Views
DragAndDrop
This is a migrated thread and some comments may be shown as answers.
Michael
Top achievements
Rank 1
Michael asked on 24 Apr 2012, 02:59 PM
I'm using DragDropManager to reposition ListViewItems within a single ListView. How can I prevent a ListViewItem from being dragged out of the ListView? RadDragAndDropManager used to have a DragQueryEvent, but I cannot find a similar event with the new  DragDropManager  framework.

8 Answers, 1 is accepted

Sort by
0
Nick
Telerik team
answered on 25 Apr 2012, 03:12 PM
Hi Michael,

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! 

Greetings,
Nik
the Telerik team

Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

0
Michael
Top achievements
Rank 1
answered on 26 Apr 2012, 08:07 AM
I've added handlers for DragLeave and QueryContinueDrag.
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
0
Nick
Telerik team
answered on 26 Apr 2012, 11:31 AM
Hello 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! 

Kind regards,
Nik
the Telerik team

Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

0
Michael
Top achievements
Rank 1
answered on 27 Apr 2012, 07:20 AM
Hello Nick,

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"
        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

0
Accepted
Nick
Telerik team
answered on 27 Apr 2012, 01:04 PM
Hello 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! 

Kind regards,
Nik
the Telerik team

Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

0
Michael
Top achievements
Rank 1
answered on 30 Apr 2012, 07:43 AM
Hello Nik,

thanks, adding a DragOver-Handler to the treeview solved my problem.

Regards,
Michael
1
Noel
Top achievements
Rank 1
answered on 16 Mar 2015, 06:54 PM
For anyone else out there who is just using the default content of their listboxitems for the drag drop visual and you are wondering why a listbox item's content seems to "vanish" after you dropped the drag visual item in question into an invalid area, the following might help you out or perhaps someone at Telerik might correct my "work around" for a listboxitem's content seemingly "vanishing" but the listboxitem itself, if using an observable collection for the SourceItems of the your lisbox control, seems to still be in place (typically just a very thin selection box remains.

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.
Ross
Top achievements
Rank 1
commented on 02 Dec 2021, 05:26 AM

After 5 hours of looking through years of forums and documentation, this was the ONLY solution that resolved my issues. Thank you! 
0
Kalin
Telerik team
answered on 17 Mar 2015, 02:03 PM
Hi Noel,

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.

 
Tags
DragAndDrop
Asked by
Michael
Top achievements
Rank 1
Answers by
Nick
Telerik team
Michael
Top achievements
Rank 1
Noel
Top achievements
Rank 1
Kalin
Telerik team
Share this question
or