项目需要实现一个DataGrid拖动排序,于是参考网上一些资源然后,修改了下实现了一个附加属性类,如下
使用方法
<DataGrid x:Name="shareGrid" test:DragDropRowBehavior.Enabled="True" test:DragDropRowBehavior.DropFinish="{Binding TestCommand}" />
DropFinish有在鼠标释放时调用,参数中包含了 拖动的数据,行号,目标行号,目标数据等。
源码:
public static class DataGridDragDropRowBehavior { public delegate Point GetDragDropPosition(IInputElement theElement); public static DependencyProperty DropFinishProperty = DependencyProperty.RegisterAttached("DropFinish", typeof(ICommand), typeof(DataGridDragDropRowBehavior), new UIPropertyMetadata(null)); public static void SetDropFinish(UIElement target, ICommand value) { target.SetValue(DropFinishProperty, value); } public static bool GetEnabled(DependencyObject obj) { return (bool)obj.GetValue(EnabledProperty); } public static void SetEnabled(DependencyObject obj, bool value) { obj.SetValue(EnabledProperty, value); } public static readonly DependencyProperty EnabledProperty = DependencyProperty.RegisterAttached("Enabled", typeof(bool), typeof(DataGridDragDropRowBehavior), new PropertyMetadata(false, OnEnableChanged)); private static void OnEnableChanged(DependencyObject depObject, DependencyPropertyChangedEventArgs e) { var dataGrid = depObject as DataGrid; var enable = (bool)e.NewValue; if (enable) { dataGrid.AllowDrop = true; dataGrid.PreviewMouseLeftButtonDown += DataGrid_PreviewMouseLeftButtonDown; dataGrid.Drop += DataGrid_Drop; } else { dataGrid.PreviewMouseLeftButtonDown -= DataGrid_PreviewMouseLeftButtonDown; dataGrid.Drop -= DataGrid_Drop; } } private static void DataGrid_Drop(object sender, DragEventArgs e) { DragItem dragitem = e.Data.GetData("DragItem") as DragItem; if (dragitem.RowIndex < 0) { return; } DataGrid datagrid = sender as DataGrid; int index = GetDataGridItemCurrentRowIndex(e.GetPosition, datagrid); //The current Rowindex is -1 (No selected) if (index < 0) { return; } //If Drag-Drop Location are same if (index == dragitem.RowIndex) { return; } var targetItem = datagrid.Items[index]; DropEventArgs arg = new DropEventArgs(); arg.SourceRowIndex = dragitem.RowIndex; arg.TargetRowIndex = index; arg.Data = dragitem.Data; arg.TargetData = targetItem; var command = (ICommand)datagrid.GetValue(DropFinishProperty); if (command != null) { command.Execute(arg); } } private static void DataGrid_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { DataGrid datagrid = sender as DataGrid; var m_prevRowIndex = GetDataGridItemCurrentRowIndex(e.GetPosition, datagrid); if (m_prevRowIndex < 0) { return; } datagrid.SelectedIndex = m_prevRowIndex; var selectedItem = datagrid.Items[m_prevRowIndex]; if (selectedItem == null) { return; } DragItem dragItem = new DragItem(); dragItem.RowIndex = m_prevRowIndex; dragItem.Data = selectedItem; DataObject data = new DataObject("DragItem", dragItem); //Now Create a Drag Rectangle with Mouse Drag-Effect //Here you can select the Effect as per your choice DragDropEffects dragdropeffects = DragDropEffects.Move; if (DragDrop.DoDragDrop(datagrid, data, dragdropeffects) != DragDropEffects.None) { //Now This Item will be dropped at new location and so the new Selected Item datagrid.SelectedItem = selectedItem; } } /// <summary> /// Method checks whether the mouse is on the required Target /// Input Parameter (1) "Visual" -> Used to provide Rendering support to WPF /// Input Paraneter (2) "User Defined Delegate" positioning for Operation /// </summary> /// <param name="theTarget"></param> /// <param name="pos"></param> /// <returns>The "Rect" Information for specific Position</returns> private static bool IsTheMouseOnTargetRow(Visual theTarget, GetDragDropPosition pos) { Rect posBounds = VisualTreeHelper.GetDescendantBounds(theTarget); Point theMousePos = pos((IInputElement)theTarget); return posBounds.Contains(theMousePos); } private static DataGridRow GetDataGridRowItem(DataGrid dataGrid, int index) { if (dataGrid.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) { return null; } return dataGrid.ItemContainerGenerator.ContainerFromIndex(index) as DataGridRow; } private static int GetDataGridItemCurrentRowIndex(GetDragDropPosition pos, DataGrid dataGrid) { int curIndex = -1; for (int i = 0; i < dataGrid.Items.Count; i++) { DataGridRow itm = GetDataGridRowItem(dataGrid, i); if (IsTheMouseOnTargetRow(itm, pos)) { curIndex = i; break; } } return curIndex; } } public class DragItem { public int RowIndex { get; set; } public object Data { get; set; } } public class DropEventArgs { public int SourceRowIndex { get; set; } public object Data { get; set; } public int TargetRowIndex { get; set; } public object TargetData { get; set; } }
参考资源:http://www.dotnetcurry.com/wpf/677/wpf-data-grid-row-drag-drop