DragDrop part2

This is similar to the dragdrop we did in this post but instead of dragging listbox items we use datagrid rows

you can see a demo here and source is here


21 thoughts on “DragDrop part2

  1. Lee,

    I tried converting this to Silverlight 2 Beta 2 and it doesn’t seem to work. Specifically, the Page doesn’t get the MouseLeftButtonDown event. Does this seem to still be working for you? Do you have any suggestions?


    David Cater

  2. Much bizarro. It’s funny how new technologies like Silverlight make you come up with innovative solutions to work around their limitations.

    Let me see if I understand this. It appears that you inserted a transparent Canvas on top of the DataGrid as a protective shield (like wrapping it in saran wrap). That prevents the DataGrid from receiving mouse events, which means they will continue up to the Page where they can be received to initiate the drag/drop. Is that accurate?

    I like that; very clever. Unfortunately, I need the DataGrid to receive mouse events. In particular, I need to use the DataGrid’s in-place editing features. If it can’t receive mouse events, those features aren’t available.

    I think I’m going to have to use an alternate approach I came up with. I don’t think it’s very elegant, but it seems to work. Since there are no preview (tunneling) mouse events, I hook the MouseLeftButtonDown event for every element in the visual tree for every row in the DataGrid. I don’t mark the event as handled when I receive it, but I do use it as an indicator that a drag may have started (followed by checking for move delta in MouseMove). So the grid is still able to handle mouse events, and editing still works.

    That’s obviously a brutal number of event hooks, but I’m not sure how much of a performance issue that is at this point. In my scenario I’m typically dealing with < 100 rows, so it may be sufficient for my needs.

    Thanks for publishing your solution. Nice work!


  3. Lets see if there is a better way than to hook up events to every element
    Please leave a comment if you find a better solution, I will do the same

  4. yes, when we do a hittest we can look for DataGridRow instead of datagrid in Page_MouseLeftButtonUp event.

    along these lines

    for (int i = 0; i < elements.Count; i++)
    DataGridRow row = elements[i] as DataGridRow;
    if (row != null)
    int index = row.GetIndex();
    //index will give target row

    we already know what the source is so, we could remove the item and add it before or after the targetrow

  5. First of all, you’re still operating in Page_MouseLeftButtonUp. In my case, I have to remove the obscuring Canvas so that the DataGrid will get mouse events. Then the mouse event gets swallowed so the Page_MouseLeftButtonUp event never gets called (because the DataGrid swallows it so the cell can be edited).

    I tried overriding Row_Loaded in the DataGrid, so I could hook DataGridRow.MouseLeftButtonUp. But once again, the DataGridRow doesn’t get MouseLeftButtonUp because its being swallowed. So far I haven’t found any other method that lets me both allow the grid cells to be edited and to allow me to see when the user has clicked on the row…but I also stopped looking because I moved on to other parts of the problem.

    Speaking of which, I’m now on the next issue, which is attempting to programmatically scroll the DataGrid. My drag is working reasonably well, but if you drag off the edge of a Datagrid with a visible scroll bar the grid doesn’t scroll. In WPF I would search for PART_VerticalScrollBar, and then execute the ScrollBar.PageDownCommand with PART_VerticalScrollBar as the IInputElement. ScrollBar in Silverlight doesn’t seem to have the same command. Any thoughts on how you would force the grid to scroll from within code?

    Also, prejeshvp, that’s what I’m working on now. My solution assumes the objects that the DataGrid is binding have a SortOrder (int) property, and that the items in dataGrid.ItemsSource are sorted by that SortOrder property. When a row is dragged I update the SortOrder values for the appropriate rows, then clear the ItemsSource and reset it (which ends up resorting again to reflect the new SortOrder values). So far it’s been a fair amount of work, so I don’t think there’s a short answer to your question.


  6. I looked at the drag/Drop and editing and could not see anything there. I was thinking may be style the datagrid to remove RowHeader and add another column which can be used for drag/drop, user will click on that column to start the Drag/Drop operation

    Did you try calling the method ScrollToVerticalOffset. In one of my posts I tried did the same

  7. Where do you see ScrollToVerticalOffset? I see ScrollIntoView, but no ScrollToVerticalOffset (in either the DataGrid or the ScrollBar).



  8. I see it now, in ScrollViewer. Unfortunately, it doesn’t look like the ControlTemplate for DataGrid uses a ScrollViewer. I’m not exactly sure why. I think I’ll use Reflector to look into the Silverlight ScrollBar and see if I can see how to do it by looking at the code. I tried setting ScrollBar.Value, and that didn’t affect the DataGrid (it just move the scroll bar thumb and that’s it).

  9. Man, it’s exhausting trying to beat Silverlight into submission sometimes. I’m stuck at the moment, short of retemplating the entire DataGrid control (which I’m trying to avoid).

    DataGrid looks for the vertical scroll bar (“VerticalScrollbarElement”). It hooks the scroll bar’s Scroll event, and when that fires it does all of the appropriate scrolling. I can’t access the internal DataGrid methods that get called to do the scrolling, and I can’t raise the Scroll event on the ScrollBar manually. I can find RepeatButtons within the ScrollBar in the visual tree, but I don’t believe you can raise a Click event on a button programmatically either.


  10. I did come up with a bit of a workaround for it. It looks like the only viable option I have for scrolling is DataGrid.ScrollIntoView. In my case I’m not going to let the user click on columns to sort them. I’m going to have an internal SortOrder member on the bound data that I sort on, and I’m going to sort the ItemsSource itself rather than letting the DataGrid do the sorting.

    Because of those limitations, I know that given a particular item in the bound list I always know what item comes before or after it in the DataGrid. If I want to scroll up, then, I can do a HitTest on the top row of the DataGrid to find out what row is at the top, then get the previous item from my data source and call DataGrid.ScrollIntoView on it. Similarly, if I want to scroll down, I get the last visible row in the DataGrid, figure out the subsequent item, and call ScrollIntoView on that.

    Ugly, but it works for me in my situation.

  11. That DevExpress DataGrid does look wicked cool. I noticed they didn’t say anything about drag/drop, though. I wonder if their control would actually help my situation at all, or if it would just be a nicer control that I still can’t bend to my will.

  12. I saw in the demo, that we can drag and drop to group items, but is kind of slow. I will wait and take a look at it as I am not in need of anything in particular as I am not working on any silverlight project

  13. Just for the record (since I think these comments are useful), I’m going to summarize some of what I’ve figured out about the mouse events in the DataGrid for drag/drop purposes:

    1. Every element in the visual tree for all rows need to hook LeftMouseButtonDown. You won’t get LeftMouseButtonDown if you hook it on the DataGrid when clicking on DataGrid cells, because the mouse event is swallowed. Use that to start the potential drag operation. You do NOT need to hook LeftMouseButtonUp and MouseMove.

    2. I’m capturing the mouse on the DataGrid object itself (not the individual UI element that was clicked on) when I get LeftMouseButtonDown, because then I will also see any MouseMove and LeftMouseButtonUp events that occur, even if the original UI element that was clicked on is disposed (which will happen if you do something to scroll the DataGrid and subsequently scroll the original UI element out of sight).

    3. Only the DataGrid itself needs to hook MouseMove and MouseLeftButtonUp. Those events will fire when you’re over the grid cells, unlike LeftMouseButtonUp. Then you can use HitTesting to figure out where you are (i.e, what row you’re over). So you do NOT need to hook MouseMove and LeftMouseButtonUp for every single item in the visual tree for all of the rows.

    4. The DataGrid will get LeftMouseButtonDown events when you click on the column headers (i.e., for sorting). If you want to disable Sorting in the DataGrid, call this.CaptureMouse() in the LeftMouseButtonDown handler for the DataGrid. Don’t expect to use that handler for any drag operations.


  14. I think as of now, these would be correct, if they do come up with preview events or bubble the events even if they are handled, like in WPF then these tasks will be simpler and efficient

  15. David, a quick question–how are you getting the list of elements in the visual tree for every row in the DataGrid., so that you can hook LeftMouseButtonDown? I’m in the same situation–I want events to get through to the DataGrid so that the user can perform sorts and the like (I don’t need editing), so I don’t want to just plaster a Canvas over the top of the grid.

    Also, has anyone played with the new agDataGrid to see if it deals with Drag and Drop any easier?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s