Drag stops on some items in grid

4 posts, 1 answers
  1. Daryl
    Daryl  avatar
    5 posts
    Member since:
    Sep 2009

    Posted 22 Oct 2009 Link to this post

    I'm modifying some code I found here for dragging items within a grid (not a datagrid). I'm dynamically adding rows to the grid to fit the number of items in an observable collection. For each cell I dynamically create a drop target that is a transparent rectangle.

    The problem: items 1 thru 3, which are initially positioned on the top row, stop being draggable once they're moved to the second row. (They can be dragged to different cells in the top row as often as you'd like.) Item 4, initially positioned in the second row, can be dragged back and forth between rows and never stops being draggable.
    The xaml is dead simple:
    <navigation:Page x:Class="EnterpriseDashboard.SL3.Views.DragTest"   
               xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"   
               xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"   
               xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
               xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
               mc:Ignorable="d" 
               xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation" 
               d:DesignWidth="640" d:DesignHeight="480" 
               Title="DragTest Page">  
          <Grid x:Name="LayoutRoot">  
          <Grid Margin="50" x:Name="dragGrid" Width="600" Height="400">  
             <Grid.ColumnDefinitions> 
                <ColumnDefinition  /> 
                <ColumnDefinition  /> 
                <ColumnDefinition /> 
             </Grid.ColumnDefinitions> 
          </Grid> 
       </Grid> 
    </navigation:Page> 

    The code is as follows:
    using System.Windows;  
    using System.Windows.Controls;  
    using System.Windows.Media;  
    using System.Windows.Shapes;  
    using System.Windows.Navigation;  
    using Telerik.Windows.Controls.DragDrop;  
    using Telerik.Windows;  
     
    namespace EnterpriseDashboard.SL3.Views  
    {  
       public partial class DragTest : Page  
       {  
          private ObservableCollection<Summary> summaries = GenerateSummaries();  
     
          public DragTest()  
          {  
             InitializeComponent();  
             //SummariesListBox.ItemsSource = summaries;  
     
             dragGrid.AddHandler(RadDragAndDropManager.DragQueryEvent, new EventHandler<DragDropQueryEventArgs>(OnDragQuery), true);  
             dragGrid.AddHandler(RadDragAndDropManager.DropQueryEvent, new EventHandler<DragDropQueryEventArgs>(OnDropQuery), true);  
             dragGrid.AddHandler(RadDragAndDropManager.DropInfoEvent, new EventHandler<DragDropEventArgs>(OnDropInfo), true);  
             dragGrid.AddHandler(RadDragAndDropManager.DragInfoEvent, new EventHandler<DragDropEventArgs>(OnDragInfo), true);  
     
             Loaded += new RoutedEventHandler(Page_Loaded);  
          }  
          void Page_Loaded(object sender, RoutedEventArgs e)  
          {  
             int col = 0;  
             int row = 0;  
             CreateRowWithDropTargets(row);  
             foreach (Summary summary in summaries)  
             {  
                if (col > 2)  
                {  
                   col = 0;  //End of row, so reset column index and create new row
                   row += 1;  
                   CreateRowWithDropTargets(row);  
                }  
                //Create a border with a textblock child -- this is the item to be dragged around.  
                var border = new Border()  
                {  
                   BorderBrush = new SolidColorBrush(Colors.Black),  
                   Background = new SolidColorBrush(Colors.White),  
                   BorderThickness = new Thickness(1),  
                   Margin = new Thickness(15)  
                };  
                var txtBlock = new TextBlock() { Text = summary.Title };  
                border.Child = txtBlock;  
                RadDragAndDropManager.SetAllowDrag(border, true);  
     
                //Add object to grid and place it in correct column and row  
                dragGrid.Children.Add(border);  
                Grid.SetColumn(border, col);  
                Grid.SetRow(border, row);  
                col += 1;  
             }  
          }  
          private void CreateRowWithDropTargets(int row)  
          {  
             dragGrid.RowDefinitions.Add(new RowDefinition());  
             for (int i = 0; i < 3; i++)  
             {  
                var dropRectangle = new Rectangle() { Fill = new SolidColorBrush(Colors.Transparent), Stroke = new SolidColorBrush(Colors.LightGray) };  
                RadDragAndDropManager.SetAllowDrop(dropRectangle, true);  
                dragGrid.Children.Add(dropRectangle);  
                Grid.SetColumn(dropRectangle, i);  
                Grid.SetRow(dropRectangle, row);  
             }  
          }  
     
          private void OnDragQuery(object sender, DragDropQueryEventArgs e)  
          {  
             if (e.Options.Status == DragStatus.DragQuery)  
             {  
                e.QueryResult = true;  
     
                //The DragAndDropmanager will detach the element and drag it around the screen.   
                var source = e.Options.Source as Border;  
                source.Visibility = Visibility.Collapsed;  
     
                e.Options.Payload = source;  
                e.Options.DragCue = new Border() { Background = new SolidColorBrush(Colors.Gray), Width = 100, Height = 100, BorderBrush = new SolidColorBrush(Colors.Gray)};  
     
                e.Handled = true;  
             }  
     
             if (e.Options.Status == DragStatus.DropSourceQuery)  
             {  
                e.QueryResult = true;  
             }  
          }  
     
          private void OnDropQuery(object sender, DragDropQueryEventArgs e)  
          {  
             if (e.Options.Status == DragStatus.DropDestinationQuery)  
             {  
                e.QueryResult = true;  
             }  
          }  
     
          private void OnDragInfo(object sender, DragDropEventArgs e)  
          {  
             if (e.Options.Status == DragStatus.DragCancel)  
             {  
                e.Options.Source.Visibility = Visibility.Visible;  
             }  
          }  
     
          private void OnDropInfo(object sender, DragDropEventArgs e)  
          {  
             if (e.Options.Status == DragStatus.DropComplete)  
             {  
                Grid.SetColumn(e.Options.Source, Grid.GetColumn(e.Options.Destination));  
                Grid.SetRow(e.Options.Source, Grid.GetRow(e.Options.Destination));  
     
                e.Options.Source.Visibility = Visibility.Visible;  
     
                e.Handled = true;  
             }  
          }  
     
     
          public static ObservableCollection<Summary> GenerateSummaries()  
          {  
             return new ObservableCollection<Summary>()  
                {  
                   new Summary(){Title = "Summary 1"},  
                   new Summary(){Title = "Summary 2"},  
                   new Summary(){Title = "Summary 3"},  
                   new Summary() {Title = "Summary 4"}  
                };  
          }  
     
          // Executes when the user navigates to this page.  
          protected override void OnNavigatedTo(NavigationEventArgs e)  
          {  
          }  
     
          public class Summary  
          {  
             public string Title { getset; }  
          }  
       }  

    Thanks for any help.
  2. Daryl
    Daryl  avatar
    5 posts
    Member since:
    Sep 2009

    Posted 23 Oct 2009 Link to this post

    Followup: It turns out that any item cannot continue to be draggable if it is dragged to a row dynamically created -after- the row of that content item.

    Lemme explain: Item A is created in row 1. Item B is created in row 2. Item C is created in row 3.  If item A is dragged to row 2, it stops being draggable. If B is dragged to row 3, it stops being draggable. But B can remain draggable in rows 1 and 2, and C remains draggable anywhere.

    My (temporary) fix was to create all the rows first, then populate with items. As long as rows 1-3 are created before A is created, A can go anywhere, and likewise for B and C.

    This fix is only temporary however, if I need to add a row after the items are created, I'll have the same problem. I cannot detect why the item stops being draggable. Is this a bug?

    Workaround: I suppose I could tear down the entire grid and repopulate, but then I have to keep track of last known dragged positions. That's not optimal, obviously.

    --d
  3. DevCraft banner
  4. Answer
    Miroslav
    Admin
    Miroslav avatar
    922 posts

    Posted 28 Oct 2009 Link to this post

    Hi Daryl ,

    I am sorry for the delayed reply.

    Thank you for the sample code, it is much easier to figure out what is the problem this way.

    There is no need to recreate everything.

    The unexpected behavior happens because when you move the elements from the first row to the second row they overlap with the drop targets in the second row. The drop targets are above them because objects are visually ordered first by their ZIndex and then by the index in the children collection of their parent. The drop targets in the second row are added after the summaries in the first row and they therefore appear above them.

    To fix this, you simply need to assign a ZIndex that is above 1 to the summaries. This way they will always be over the drop targets.

    I gave modifies your code to do this and I am attaching it here.

    Here is how I modified the creation method:

    void Page_Loaded(object sender, RoutedEventArgs e)
    {
        int col = 0;
        int row = 0;
        CreateRowWithDropTargets(row);
      
        var summaryZIndex = 1;
        foreach (Summary summary in summaries)
        {
            if (col > 2)
            {
                col = 0;  //End of row, so reset column index and create new row 
                row += 1;
                CreateRowWithDropTargets(row);
            }
            //Create a border with a textblock child -- this is the item to be dragged around.   
            var border = new Border()
            {
                BorderBrush = new SolidColorBrush(Colors.Black),
                Background = new SolidColorBrush(Colors.White),
                BorderThickness = new Thickness(1),
                Margin = new Thickness(15)
            };
      
            Canvas.SetZIndex(border, summaryZIndex++);
      
            var txtBlock = new TextBlock() { Text = summary.Title };
            border.Child = txtBlock;
            RadDragAndDropManager.SetAllowDrag(border, true);
      
            //Add object to grid and place it in correct column and row   
            dragGrid.Children.Add(border);
            Grid.SetColumn(border, col);
            Grid.SetRow(border, row);
            col += 1;
        }
    }

    Hopefully this will work for you,

    Sincerely yours,
    Miroslav
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
  5. Daryl
    Daryl  avatar
    5 posts
    Member since:
    Sep 2009

    Posted 28 Oct 2009 Link to this post

    Thanks, Miroslav! I think that will do it.
Back to Top