DataGrid control in WPF is a rich table structured control, which is perfect for displaying any kind of data in table like format. The one think about DataGrid it always lack, is a possibility to easily change the order of rows. It is not even about drag and drop of rows and items from and into the DataGrid , but simply rearrange existing rows in DataGrid control. It this post I will present you my solution for this problem, which additionally sticks to MvvM pattern perfectly.
There are many solutions for this problem in the internet., for instance here, here or here, but those all always involve a code behind implementation of this feature. There are two things about that that I couldn’t accept. One is that this is not in accordance with MvvM pattern which assumes no code behind. Ok, one could say this is strictly a “view” related code, but still, I don’t like it. The second thing, and the reason I write this post for, is fact that having this code in code behind files does not stick to DRY principle. We would need to copy it for every window or control where we want to have this feature implemented.
Saying that, I have decided to implement a movable rows in DataGrid as a attached dependency property, so I am able to attach it to every DataGrid control I want with just a one line of XAML.
Let’s start by creating a helper class VisualHelper and defining a attached dependency porperty in in, which will enable the MOvable rows on target DataGrid
Next thing is to implement the EnableRowsMoveChange methos which will be fired every time the attached property EnableRowsMove is changed. Inside this method we need to register three mouse events on our DataGrid control.
I think, it is quite trivial, we only assign those events to controls which are a DataGrid. Now there is one tricky thing in my implementation. When we move row with mouse move, we need to somehow remember the source item, we started dragging, so at the end, when we release mouse button, we know which item to replace with final row. We cannot use a static property or field on VisualHelper class, because it could cause interference if we have more than one DataGrid with movablr rows. So we can do it with attached property as well, but we will mark them as private, so it can be used only inside a VisualHelper class.
As you can see we marked the attached property as well as property getter and setter as private, so there is no access to this property from XAML.
Now we can implement the rest of mouse events.
As shown above we also exchange source and target item on mouse move over the DataGrid. This gives a pretty effect of moving rows up and down while we are moving mouse cursor. One important thing here is the requirement we set on the DataGrid to be able to service the movable rows. This is the ItemsSource property to be set to at least IList implemented collection or even better to an ObservableCollection. This is because we not actually moving the DataGrid rows but we are moving items on underlying collection, and to have it possible we need it to implement at least IList interface. But to have changes in rows also visible on the grid we need to bind it to a ObservableCollection or other collection which implement INotifyCollectionChanged basically.
Having that in place, all we need is to decorate our DataGrid control in xaml
Full solution for this post is available in attached file.