Prevent drop if outside destination

9 posts, 1 answers
  1. Michael
    Michael avatar
    34 posts
    Member since:
    Oct 2009

    Posted 24 Apr 2012 Link to this post

    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.
  2. Nick
    Admin
    Nick avatar
    593 posts

    Posted 25 Apr 2012 Link to this post

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

  3. UI for WPF is Visual Studio 2017 Ready
  4. Michael
    Michael avatar
    34 posts
    Member since:
    Oct 2009

    Posted 26 Apr 2012 Link to this post

    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
  5. Nick
    Admin
    Nick avatar
    593 posts

    Posted 26 Apr 2012 Link to this post

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

  6. Michael
    Michael avatar
    34 posts
    Member since:
    Oct 2009

    Posted 27 Apr 2012 Link to this post

    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

  7. Answer
    Nick
    Admin
    Nick avatar
    593 posts

    Posted 27 Apr 2012 Link to this post

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

  8. Michael
    Michael avatar
    34 posts
    Member since:
    Oct 2009

    Posted 30 Apr 2012 Link to this post

    Hello Nik,

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

    Regards,
    Michael
  9. Noel
    Noel avatar
    3 posts
    Member since:
    Feb 2013

    Posted 16 Mar 2015 Link to this post

    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.
  10. Kalin
    Admin
    Kalin avatar
    1207 posts

    Posted 17 Mar 2015 Link to this post

    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.

     
Back to Top
UI for WPF is Visual Studio 2017 Ready