This one gave me some headache, but as always, looking back the solution is pretty obvious.

Using WPF, in a MVVM design pattern, I have a ListView bound to a ObservableCollection. Straight forward senario.

XAML:

<ListView Name="lvCustomerSearchResults" ItemsSource="{Binding CustomerSearchResults}" SelectedItem="{Binding SelectedCustomer}" ...

 

ViewModel:

 

public async Task<AOTaskResult<List<CustomerSearchResultEntity>>> SearchCustomers(string cvrNo, Statuses? status = null, DateTime? fromDate = null, DateTime? toDate = null)
{
    return await Task.Run(() =>
    {
        AOTaskResult<List<CustomerSearchResultEntity>> result = new AOTaskResult<List<CustomerSearchResultEntity>>();
        try
        {
            result.Response = _repository.LstCustomers(cvrNo, status, fromDate, toDate, out List<NezCusCustomerDTO> dtos);
            if (result.Response.Success)
            {
                result.Result = dtos.Select(d => LocalMapping.ToCustomerSearchResultEntity(d)).ToList();
            }
        }
        catch (Exception ex) { CheckTaskException(ex); }
        return result;
    });
}

 

Trouble is when I click an item in the ListWiew I get a “Must create DependencySource on same Thread as the DependencyObject”-exception. It turns out that the reason I get this exception is that I created the items in the ObservableCollection on another thread than the main-thread. So, obviously, the solution is to create the the ObservableCollection items on the main-thread:

public async Task<AOTaskResult<List<CustomerSearchResultEntity>>> SearchCustomers(string cvrNo, Statuses? status = null, DateTime? fromDate = null, DateTime? toDate = null)
{
    AOTaskResult<List<CustomerSearchResultEntity>> result = new AOTaskResult<List<CustomerSearchResultEntity>>();
    List<NezCusCustomerDTO> dtos = null;

    await Task.Run(() =>
    {
        try
        {
            Busy = true;
            result.Response = _repository.LstCustomers(cvrNo, status, fromDate, toDate, out dtos);

            Busy = false;
        }
        catch (Exception ex) { CheckTaskException(ex); }
    });
    if (dtos != null && result.Response.Success)
    {
        result.Result = dtos.Select(d => LocalMapping.ToCustomerSearchResultEntity(d)).ToList();
    }
    return result;
}

 

 IMO, the code is not as clean ... but it works :-)

 

As always feel to ask or comment.


A Simple WPF DataGrid using MVVM

Published 9/15/2017 by Christian in Code
Tags: , , ,

Her follows a simple WPF DataGrid.

In the Visual Studio Design view it look like this:

The DefaultButtonStyle and DefaultDataGrid style can be found elsewhere in this blog.

Ill include the XAML for the entire Window.

<Window x:Class="Ellab.Main.Sessions.Chamber.WPFUnitSelection.UnitSelectionView"
        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"
        xmlns:local="clr-namespace:Ellab.Main.Sessions.Chamber.WPFUnitSelection"
        mc:Ignorable="d"
        Title="{Binding Title}" x:Name="MainWindow" Height="300" Width="750">
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/Ellab.WPF;component/View/Styles/ButtonStyle.xaml"/>
                <ResourceDictionary Source="pack://application:,,,/Ellab.WPF;component/View/Styles/DataGridStyle.xaml"/>
                <ResourceDictionary Source="MvvmResources.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
    <Grid Background="{Binding Background, FallbackValue=Red}">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="40"/>
        </Grid.RowDefinitions>
        <DataGrid Grid.Row="0" ItemsSource="{Binding Rows, FallbackValue=AllTheSmartRows}" Style="{StaticResource DefaultDataGrid}" HeadersVisibility="Column" AutoGenerateColumns="False" VerticalAlignment="Top" SelectionMode="Single" SelectionUnit="FullRow" SelectedItem="{Binding SelectedItem}">
            <DataGrid.RowStyle>
                <Style TargetType="{x:Type DataGridRow}">
                    <EventSetter Event="MouseLeftButtonDown" Handler="DataGrid_MouseLeftButtonDown"/>
                    <Style.Triggers>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter Property="Background" Value="#FF009CDD" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </DataGrid.RowStyle>
            <DataGrid.Columns>
                <DataGridTextColumn Header="{Binding UnitIDHeader, FallbackValue=ID}" Binding="{Binding UnitID, FallbackValue=ID}" MinWidth="75" Width="Auto" IsReadOnly="True"/>
                <DataGridTextColumn Header="{Binding TypeHeader, FallbackValue=Type}" Binding="{Binding Type, FallbackValue=Type}" MinWidth="75" Width="Auto" IsReadOnly="True"/>
                <DataGridTextColumn Header="{Binding UnitTypeHeader, FallbackValue=Unit Type}" Binding="{Binding UnitType, FallbackValue=Unit}" MinWidth="75" Width="Auto" IsReadOnly="True"/>
                <DataGridTextColumn Header="{Binding NameHeader, FallbackValue=Name}" Binding="{Binding Name, FallbackValue=Name}" MinWidth="125" Width="Auto" IsReadOnly="True"/>
                <DataGridTextColumn Header="{Binding DescriptionHeader, FallbackValue=Description}" Binding="{Binding Description, FallbackValue=Description}" MinWidth="25" Width="*" IsReadOnly="True"/>
            </DataGrid.Columns>
        </DataGrid>
        <Grid Grid.Row="1" Background="White" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Height="40">
            <StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" HorizontalAlignment="Right">
                <Button Margin="5" Command="{Binding HelpClickedCommand}" Width="30" Style="{StaticResource DefaultButtonStyle}" Background="#FF123F74">
                    <Image Source="../../Resources/Help.png"/>
                </Button>
                <Button Margin="5" Content="{Binding ViewButtonContent, FallbackValue=#View}" Command="{Binding ViewClickedCommand}" Style="{StaticResource DefaultButtonStyle}" Visibility="{Binding ViewVisible}" MinWidth="75"/>
                <Button Margin="5" Content="{Binding AddNewButtonContent, FallbackValue=#Add New}" Command="{Binding AddNewClickedCommand}" Style="{StaticResource DefaultButtonStyle}" Visibility="{Binding AddNewVisible}" MinWidth="75"/>
                <Button Margin="5" Content="{Binding EditButtonContent, FallbackValue=#Edit}" Command="{Binding EditClickedCommand}" Style="{StaticResource DefaultButtonStyle}" Visibility="{Binding EditVisible}" MinWidth="75"/>
                <Button Margin="5" Content="{Binding RemoveButtonContent, FallbackValue=#Remove}" Command="{Binding RemoveClickedCommand}" Style="{StaticResource DefaultButtonStyle}" Visibility="{Binding RemoveVisible}" MinWidth="75"/>
                <Button Margin="5" Content="{Binding ImportButtonContent, FallbackValue=#Import}" Command="{Binding ImportClickedCommand}" Style="{StaticResource DefaultButtonStyle}" Visibility="{Binding ImportVisible}" MinWidth="75"/>
                <Button Margin="5" Content="{Binding ExportButtonContent, FallbackValue=#Export}" Command="{Binding ExportClickedCommand}" Style="{StaticResource DefaultButtonStyle}" Visibility="{Binding ExportVisible}" MinWidth="75"/>
                <Button Margin="5" Content="{Binding OKButtonContent, FallbackValue=#OK}" Command="{Binding OKClickedCommand}" Style="{StaticResource DefaultButtonStyle}" Visibility="{Binding OKVisible}" IsDefault="True" MinWidth="75"/>
                <Button Margin="5" Content="{Binding CloseButtonContent, FallbackValue=#Close}" Command="{Binding CloseClickedCommand}" Style="{StaticResource DefaultButtonStyle}" Visibility="{Binding CloseVisible}" IsCancel="True" MinWidth="75"/>
            </StackPanel>
        </Grid>
    </Grid>
</Window>

Allthough using the MVVM design patten, I've opted to handel  event in the codebehind, as in my opinion this is View releated. Here is the event handler

namespace Ellab.Main.Sessions.Chamber.WPFUnitSelection
{
    /// <summary>
    /// Interaction logic for UnitSelectionView.xaml
    /// </summary>
    public partial class UnitSelectionView : Window
    {
        private UnitSelectionView()
        {
            InitializeComponent();
        }

        public UnitSelectionView(UnitSelectionViewModel mainContext)
            : this()
        {
            DataContext = mainContext;
        }
        private void DataGrid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            DataGridRow clickedRos = sender as DataGridRow;
            clickedRos.IsSelected = true;
        }
    }
}

As always, feel free to comment, or ask.


Getting an ancestor property value can be done by binding to its element name. Here's an example

<Grid Width="{Binding Width}" Margin="{Binding Margin}">
	<Border BorderBrush=" #FF17447E" BorderThickness="5">
		<StackPanel Name="MainStackPanel" Orientation="Vertical">
			<ScrollViewer Height="{Binding ElementName=MainStackPanel, Path=ActualHeight}">
				<ItemsControl ItemsSource="{Binding Rows, FallbackValue=Rows}" Background="Transparent">
					<ItemsControl.ItemsPanel>
						<ItemsPanelTemplate>
							<StackPanel Orientation="Vertical"/>
						</ItemsPanelTemplate>
					</ItemsControl.ItemsPanel>
					<ItemsControl.ItemTemplate>
						<DataTemplate>
							<ContentPresenter Content="{Binding}" Height="30"/>
						</DataTemplate>
					</ItemsControl.ItemTemplate>
				</ItemsControl>
			</ScrollViewer>
		</StackPanel>
	</Border>
</Grid>

As always, feel free to comment, or ask


OK - So I’ve got a WPF DataGrid, with a DataGridTemplateColumn. The DataTemplate is a plane TextBox. When I tab through the cells, I want to select the text in the TextBox. And when I click the text in the TextBox, I also want to select it. That proved more difficult than I expected.

But hacking and slashing from this blog

http://andora.us/blog/2011/06/09/wpf-textbox-select-all-on-focus/

and this answer

http://stackoverflow.com/questions/1104164/wpf-datagridtemplatecolumn-am-i-missing-something

I came up with a solution. Although not strictly MVVM, I still think it falls under that design pattern. All View related stuff is still handled in the View.

Anyway - First of all. when you tab through the cells the first tab stop is the border of the cell, and the second is the actual TextBox.

Secondly, In WPF, the default behavior of the TextBox on focus is to put the cursor where it was the last time the TextBox had lost focus or if it hasn’t had focus yet, at the beginning.

The first problem I solved by by using the answer from stackoverflow:

<DataGridTemplateColumn.CellStyle>
	<Style TargetType="{x:Type DataGridCell}">
		<Setter Property="KeyboardNavigation.IsTabStop" Value="False"/>
	</Style>
</DataGridTemplateColumn.CellStyle>

The second by following Andora block. So the hole XAML DataGrid looks like this:

<DataGrid Name="TextBlockDataGrid" ItemsSource="{Binding Path=Rows}" Style="{StaticResource DefaultSettingsDataGrid}">
	<DataGrid.Columns>
		<DataGridTextColumn Binding="{Binding Text}" IsReadOnly="True"/>
		<DataGridTemplateColumn Width="*">
			<DataGridTemplateColumn.CellStyle>
				<Style TargetType="{x:Type DataGridCell}">
					<Setter Property="KeyboardNavigation.IsTabStop" Value="False"/>
				</Style>
			</DataGridTemplateColumn.CellStyle>
			<DataGridTemplateColumn.CellTemplate>
				<DataTemplate>
					<Border BorderThickness="{Binding ErrorBorderThickness}" BorderBrush="{Binding ErrorBorderBrush}">
						<TextBox Text="{Binding UserText, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" 
								 HorizontalAlignment="Right" 
								 GotKeyboardFocus="TextBox_GotKeyboardFocus" 
								 PreviewMouseDown="TextBox_PreviewMouseDown"
								 Style="{StaticResource DefaultTextBox}"/>
					</Border>
				</DataTemplate>
			</DataGridTemplateColumn.CellTemplate>
		</DataGridTemplateColumn>
	</DataGrid.Columns>
</DataGrid>

And the code-behind like this:

private void TextBox_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
	try
	{
		((TextBox)sender).SelectAll();
	}
	catch { }
}

private void TextBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
	try
	{
		// If its a triple click, select all text for the user.
		if (e.ClickCount == 3)
		{
			((TextBox)sender).SelectAll();
			return;
		}

		// Find the TextBox
		DependencyObject parent = e.OriginalSource as UIElement;
		while (parent != null && !(parent is TextBox))
		{
			parent = System.Windows.Media.VisualTreeHelper.GetParent(parent);
		}

		if (parent != null)
		{
			if (parent is TextBox)
			{
				var textBox = (TextBox)parent;
				if (!textBox.IsKeyboardFocusWithin)
				{
					// If the text box is not yet focussed, give it the focus and
					// stop further processing of this click event.
					textBox.Focus();
					e.Handled = true;
				}
			}
		}
	}
	catch { }
}

 

As always, feel free to comment, or ask.


Text - or anything else for that matter - can be scaled  to fill all available space by using a Viewbox. Here is an example.

<Viewbox HorizontalAlignment="Center" VerticalAlignment="Center">
	<TextBlock Text="{Binding Path=HeadlineText}"/>
</Viewbox>

As always, feel free to comment, or ask.


There are of course a lot of ways to collapse a XAML TextBlock, but here is one using a style.

<TextBlock Text="{Binding Path=DescriptiveText}">
	<TextBlock.Style>
		<Style TargetType="TextBlock">
			<Style.Triggers>
				<Trigger Property="Text" Value="{x:Null}">
					<Setter Property="Visibility" Value="Collapsed" />
				</Trigger>
				<Trigger Property="Text" Value="">
					<Setter Property="Visibility" Value="Collapsed" />
				</Trigger>
			</Style.Triggers>
		</Style>
	</TextBlock.Style>
</TextBlock>

As always, feel free to comment, or ask.


This post is about how control events, like MouseDoubleClick, MouseEnter ect., can be handled in a MVVM design

First a general Behaviour class

public static partial class Behaviours
{
	public static class EventBehaviourFactory
	{
		public static DependencyProperty CreateCommandExecutionEventBehaviour(RoutedEvent routedEvent, string propertyName, Type ownerType)
		{
			DependencyProperty property = DependencyProperty.RegisterAttached(propertyName, typeof(ICommand), ownerType,
				new PropertyMetadata(null,
					new ExecuteCommandOnRoutedEventBehaviour(routedEvent).PropertyChangedHandler));

			return property;
		}

		/// <summary>
		/// An internal class to handle listening for an event and executing a command,
		/// when a Command is assigned to a particular DependencyProperty
		/// </summary>
		private class ExecuteCommandOnRoutedEventBehaviour : ExecuteCommandBehaviour
		{
			private readonly RoutedEvent _routedEvent;

			public ExecuteCommandOnRoutedEventBehaviour(RoutedEvent routedEvent)
			{
				_routedEvent = routedEvent;
			}

			/// <summary>
			/// Handles attaching or Detaching Event handlers when a Command is assigned or unassigned
			/// </summary>
			/// <param name="sender"></param>
			/// <param name="oldValue"></param>
			/// <param name="newValue"></param>
			protected override void AdjustEventHandlers(DependencyObject sender, object oldValue, object newValue)
			{
				UIElement element = sender as UIElement;
				if (element == null) { return; }

				if (oldValue != null)
				{
					element.RemoveHandler(_routedEvent, new RoutedEventHandler(EventHandler));
				}

				if (newValue != null)
				{
					element.AddHandler(_routedEvent, new RoutedEventHandler(EventHandler));
				}
			}

			protected void EventHandler(object sender, RoutedEventArgs e)
			{
				HandleEvent(sender, e);
			}
		}

		internal abstract class ExecuteCommandBehaviour
		{
			protected DependencyProperty _property;
			protected abstract void AdjustEventHandlers(DependencyObject sender, object oldValue, object newValue);

			protected void HandleEvent(object sender, EventArgs e)
			{
				DependencyObject dp = sender as DependencyObject;
				if (dp == null)
				{
					return;
				}

				ICommand command = dp.GetValue(_property) as ICommand;

				if (command == null)
				{
					return;
				}

				if (command.CanExecute(e))
				{
					command.Execute(e);
				}
			}

			/// <summary>
			/// Listens for a change in the DependencyProperty that we are assigned to, and
			/// adjusts the EventHandlers accordingly
			/// </summary>
			/// <param name="sender"></param>
			/// <param name="e"></param>
			public void PropertyChangedHandler(DependencyObject sender, DependencyPropertyChangedEventArgs e)
			{
				// the first time the property changes,
				// make a note of which property we are supposed
				// to be watching
				if (_property == null)
				{
					_property = e.Property;
				}

				object oldValue = e.OldValue;
				object newValue = e.NewValue;

				AdjustEventHandlers(sender, oldValue, newValue);
			}
		}
	}
}

The ControlEventBehaviour class

public class ControlEventBehaviour
{
	#region Button
	public static readonly DependencyProperty MouseEnterCommand = Behaviours.EventBehaviourFactory.CreateCommandExecutionEventBehaviour
			 (Button.MouseEnterEvent, "MouseEnterCommand", typeof(ControlEventBehaviour));

	public static void SetMouseEnterCommand(DependencyObject o, ICommand value)
	{
		o.SetValue(MouseEnterCommand, value);
	}

	public static ICommand GetMouseEnterCommand(DependencyObject o)
	{
		return o.GetValue(MouseEnterCommand) as ICommand;
	}

	public static readonly DependencyProperty MouseLeaveCommand = Behaviours.EventBehaviourFactory.CreateCommandExecutionEventBehaviour
		 (Button.MouseLeaveEvent, "MouseLeaveCommand", typeof(ControlEventBehaviour));

	public static void SetMouseLeaveCommand(DependencyObject o, ICommand value)
	{
		o.SetValue(MouseLeaveCommand, value);
	}

	public static ICommand GetMouseLeaveCommand(DependencyObject o)
	{
		return o.GetValue(MouseLeaveCommand) as ICommand;
	}

	public static readonly DependencyProperty MouseDoubleClickCommand = Behaviours.EventBehaviourFactory.CreateCommandExecutionEventBehaviour
		 (Button.MouseDoubleClickEvent, "MouseDoubleClickCommand", typeof(ControlEventBehaviour));

	public static void SetMouseDoubleClickCommand(DependencyObject o, ICommand value)
	{
		o.SetValue(MouseDoubleClickCommand, value);
	}

	public static ICommand GetMouseDoubleClickCommand(DependencyObject o)
	{
		return o.GetValue(MouseDoubleClickCommand) as ICommand;
	}
	#endregion Button
}

The shown example only handle button events, but with slight modification can be used for all WPF controls.

In the View:

<Button Command="{Binding Path=ButtonClickCommand}"
		utilities:ControlEventBehaviour.MouseEnterCommand="{Binding Path=MouseEnter}"
		utilities:ControlEventBehaviour.MouseLeaveCommand="{Binding Path=MouseLeave}"
		utilities:ControlEventBehaviour.MouseDoubleClickCommand="{Binding Path=ButtonDoubleClick}">

And finally in the ViewModel. This is only for MouseEnter, but I'm sure that you get the gist of it :)

private RelayCommand _mouseEnter = null;
public virtual RelayCommand MouseEnter
{
	get
	{
		if (_mouseEnter == null)
		{
			_mouseEnter = new RelayCommand(param =>
			{
				try
				{
				}
				catch { }
			}, param => { return true; });
		}
		return _mouseEnter;
	}
}

As always, feel free to comment, or ask.


TextBlock with vertical text

Published 10/31/2014 by Christian
Tags: ,

This will make the text in the TextBlock vertical

<TextBlock Text="Some Text">
	<TextBlock.LayoutTransform>
		<TransformGroup>
			<RotateTransform Angle="90" />
			<ScaleTransform ScaleX="-1" ScaleY="-1"/>
		</TransformGroup>
	</TextBlock.LayoutTransform>
</TextBlock>

As always, feel free to comment, or ask.


XAML style inheritance

Published 10/31/2014 by Christian
Tags: , ,

This makes the Bar style inherits from Foo

<ResourceDictionary x:Class="Baltz.Styles.Bar"
                    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                    xmlns:d="http://schemas.microsoft.com/expression/blend/2008">
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Foo.xaml"/>
    </ResourceDictionary.MergedDictionaries>
    <Style x:Key="aKey" BasedOn="{StaticResource StyleInFoo}" TargetType="{x:Type aType}">
        <Setter Property="aTypeProperty" Value="aTypePropertyvalue"/>
    </Style>
</ResourceDictionary>

As always, feel free to comment, or ask.


 It took me some time to find a solution to this problem, but here is a working solution.

 

 I wanted to be able to drag 'n drop WPF DataGrid rows in MVVM, and although this solution is not strickly MVVM, I still think that it fits nicely in that design patten. All GUI it handled within the view, and all logic in the ViewModel.

 I found a good starting point for this solution somewhere, but again unfortunately I have forgotten where. I think it was on codeproject. My sincere apologies to the author.

 The follwing goes into the UserControl code behind:

using Baltz.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Baltz.View
{
    /// <summary>
    /// Interaction logic for DataGridDraggableRowView.xaml
    /// </summary>
    public partial class DataGridDraggableRowView : UserControl
    {
        public DataGridDraggableRowView()
        {
            InitializeComponent();
        }

        #region Static Methods
        private static T FindVisualParent<T>(UIElement element) where T : UIElement
        {
            var parent = element;
            while (parent != null)
            {
                var correctlyTyped = parent as T;
                if (correctlyTyped != null)
                {
                    return correctlyTyped;
                }

                parent = VisualTreeHelper.GetParent(parent) as UIElement;
            }
            return null;
        }
        #endregion

        #region Fields
        private int _originalIndex;
        private DataGridRow _oldRow;
        private DataGridDraggableRowItem _targetItem;
        private DataGridDraggableRowViewModel _viewModel;
        #endregion Fields

        #region Event Handlers
        /// <summary>
        /// Updates the grid as a drag progresses
        /// </summary>
        private void OnMainGridCheckDropTarget(object sender, DragEventArgs e)
        {
            var row = FindVisualParent<DataGridRow>(e.OriginalSource as UIElement);

            // Set the DragDropEffects 
            if ((row == null) || !(row.Item is DataGridDraggableRowItem))
            {
                e.Effects = DragDropEffects.None;
            }
            else
            {
                var currentIndex = row.GetIndex();

                // Erase old drop-line
                if (_oldRow != null)
                    _oldRow.BorderThickness = new Thickness(0);

                // Draw new drop-line
                var direction = (currentIndex - _originalIndex);
                if (direction < 0)
                    row.BorderThickness = new Thickness(0, 2, 0, 0);
                else if (direction > 0)
                    row.BorderThickness = new Thickness(0, 0, 0, 2);
                row.BorderBrush = new SolidColorBrush(Color.FromArgb(0xFF, 0x00, 0x9C, 0xDD));
                // Reset old row
                _oldRow = row;
            }
        }

        /// <summary>
        /// Gets the view model from the data Context and assigns it to a member variable.
        /// </summary>
        private void OnMainGridDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            _viewModel = (DataGridDraggableRowViewModel)this.DataContext;
        }

        /// <summary>
        /// Process a row drop on the DataGrid.
        /// </summary>
        private void OnMainGridDrop(object sender, DragEventArgs e)
        {
            e.Effects = DragDropEffects.None;
            e.Handled = true;

            // Verify that this is a valid drop and then store the drop target
            var row = FindVisualParent<DataGridRow>(e.OriginalSource as UIElement);
            if (row != null)
            {
                _targetItem = row.Item as DataGridDraggableRowItem;
                if (_targetItem != null)
                {
                    e.Effects = DragDropEffects.Move;
                }
            }

            // Erase last drop-line
            if (_oldRow != null)
                _oldRow.BorderThickness = new Thickness(0, 0, 0, 0);
        }

        /// <summary>
        /// Processes a drag in the main grid.
        /// </summary>
        private void OnMainGridMouseMove(object sender, MouseEventArgs e)
        {
            // Exit if left mouse button aren't pressed
            if (e.LeftButton != MouseButtonState.Pressed)
                return;

            // Find the row the mouse button was pressed on
            var row = FindVisualParent<DataGridRow>(e.OriginalSource as FrameworkElement);
            _originalIndex = row.GetIndex();

            // If the row was already selected, begin drag
            if ((row != null) && row.IsSelected)
            {
                // Get the grocery item represented by the selected row
                var selectedItem = (DataGridDraggableRowItem)row.Item;
                var finalDropEffect = DragDrop.DoDragDrop(row, selectedItem, DragDropEffects.Move);
                if ((finalDropEffect == DragDropEffects.Move) && (_targetItem != null))
                {
                    /* A drop was accepted. Determine the index of the item being 
                     * dragged and the drop location. If they are different, then 
                     * move the selectedItem to the new location. */

                    // Move the dragged item to its drop position
                    var oldIndex = _viewModel.Rows.IndexOf(selectedItem);
                    var newIndex = _viewModel.Rows.IndexOf(_targetItem);
                    if (oldIndex != newIndex)
                        _viewModel.Rows.Move(oldIndex, newIndex);
                    _targetItem = null;
                }
            }
        }
        #endregion
    }
}

A side note: This style is based on a style posted in another post

<ResourceDictionary x:Class="Ellab.Main.Settings.SettingsWindow.View.Styles.DraggableDataGridStyle"
                    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                    mc:Ignorable="d">
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="DataGridStyle.xaml"/>
    </ResourceDictionary.MergedDictionaries>
    <Style x:Key="DefaultDraggableDataGrid" BasedOn="{StaticResource DefaultSettingsDataGrid}" TargetType="{x:Type DataGrid}">
        <Setter Property="HeadersVisibility" Value="Column"/>
        <Setter Property="AllowDrop" Value="True"/>
    </Style>
    <Style TargetType="{x:Type DataGridCell}">
        <Style.Resources>
            <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#FF009CDD" />
            <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="#FF009CDD" />
            <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" />
            <SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Black" />
        </Style.Resources>
    </Style>
</ResourceDictionary>

And this is the complete View - most of it isn't relevant for the dragable rows.

<UserControl x:Class="foo.View.barDataGridDraggableRowView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Styles/DraggableDataGridStyle.xaml"/>
                <ResourceDictionary Source="Styles/ContentPresenterStyle.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </UserControl.Resources>
    <StackPanel Orientation="Vertical" Background="Transparent">
        <ContentPresenter Content="{Binding Path=HeaderButton}" Style="{StaticResource DefaultContentPresenter}"/>
        <StackPanel Orientation="Vertical" Background="Transparent" Visibility="{Binding Path=IsExpanded}">
            <DataGrid ItemsSource="{Binding Path=Rows}"
                  MouseMove="OnMainGridMouseMove"
                  DragEnter="OnMainGridCheckDropTarget"
                  DragLeave="OnMainGridCheckDropTarget"
                  DragOver="OnMainGridCheckDropTarget"
                  Drop="OnMainGridDrop" 
                  DataContextChanged="OnMainGridDataContextChanged"
                  Style="{StaticResource DefaultDraggableDataGrid}">
                <DataGrid.Columns>
                    <DataGridTemplateColumn IsReadOnly="True" Width="20">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <Image Source="../../Resources/DragDrop.png" Stretch="Fill" Opacity="{Binding Opacity}"/>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTemplateColumn IsReadOnly="True">
                        <DataGridTemplateColumn.Header>
                            <TextBlock Text="{Binding DataContext.EnabledColumnHeader, RelativeSource={RelativeSource AncestorType=DataGrid}}" MaxWidth="65" TextWrapping="WrapWithOverflow" TextTrimming="CharacterEllipsis">
                                <TextBlock.LayoutTransform>
                                    <TransformGroup>
                                        <RotateTransform Angle="90" />
                                        <ScaleTransform ScaleX="-1" ScaleY="-1"/>
                                    </TransformGroup>
                                </TextBlock.LayoutTransform>
                            </TextBlock>
                        </DataGridTemplateColumn.Header>
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <CheckBox HorizontalAlignment="Center" VerticalAlignment="Center" IsChecked="{Binding EnabledChecked, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Opacity="{Binding Opacity}" IsEnabled="{Binding Enable}"/>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTemplateColumn IsReadOnly="True">
                        <DataGridTemplateColumn.Header>
                            <TextBlock Text="{Binding DataContext.WizardColumnHeader, RelativeSource={RelativeSource AncestorType=DataGrid}}" MaxWidth="65" TextWrapping="WrapWithOverflow" TextTrimming="CharacterEllipsis">
                                <TextBlock.LayoutTransform>
                                    <TransformGroup>
                                        <RotateTransform Angle="90" />
                                        <ScaleTransform ScaleX="-1" ScaleY="-1"/>
                                    </TransformGroup>
                                </TextBlock.LayoutTransform>
                            </TextBlock>
                        </DataGridTemplateColumn.Header>
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <CheckBox HorizontalAlignment="Center" VerticalAlignment="Center" IsChecked="{Binding WizardChecked, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Opacity="{Binding Opacity}" IsEnabled="{Binding Enable}" Visibility="{Binding WizardVisible}"/>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTemplateColumn IsReadOnly="True" Width="*">
                        <DataGridTemplateColumn.Header>
                            <TextBlock Text="{Binding DataContext.TextColumnHeader, RelativeSource={RelativeSource AncestorType=DataGrid}}" TextWrapping="WrapWithOverflow" TextTrimming="CharacterEllipsis" VerticalAlignment="Bottom"/>
                        </DataGridTemplateColumn.Header>
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Text}" HorizontalAlignment="Left" VerticalAlignment="Center" Opacity="{Binding Opacity}" IsEnabled="{Binding Enable}"/>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTemplateColumn IsReadOnly="True" Width="40">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <Image Source="{Binding TileImage}" Opacity="{Binding Opacity}"/>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                </DataGrid.Columns>
            </DataGrid>
            <ContentPresenter Content="{Binding Path=TilesRemainingText}"/>
        </StackPanel>
    </StackPanel>
</UserControl>

As always, feel free to comment, or ask.