DataGrid列排序后拖拽功能失效,需提升拖拽优先级实现共存
解决DataGrid排序后行拖拽失效的问题
问题根源
DataGrid列排序后,内部会生成排序后的ICollectionView作为实际显示数据源,而非直接使用原始的ProductCollection。若拖拽逻辑未正确处理视图与原始集合的索引映射,就会导致拖拽功能失效。
具体修复方案
1. 拖拽开始时绑定原始集合项
不要直接使用DataGrid视图的索引,转而获取原始集合中对应项的真实索引:
private Product _draggedItem; private int _originalIndex; private void DataGrid_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { var dataGrid = sender as DataGrid; var row = FindVisualParent<DataGridRow>(e.OriginalSource as DependencyObject); if (row != null && row.IsSelected) { _draggedItem = row.Item as Product; // 直接从原始集合获取索引,跳过视图层 _originalIndex = (dataGrid.ItemsSource as ProductCollection).IndexOf(_draggedItem); } }
2. 放置操作直接修改原始集合
拖拽放置时直接更新原始的ProductCollection,排序后的视图会自动同步显示:
private void DataGrid_Drop(object sender, DragEventArgs e) { var dataGrid = sender as DataGrid; var targetRow = FindVisualParent<DataGridRow>(e.OriginalSource as DependencyObject); if (targetRow != null && _draggedItem != null) { var targetItem = targetRow.Item as Product; var targetIndex = (dataGrid.ItemsSource as ProductCollection).IndexOf(targetItem); var collection = dataGrid.ItemsSource as ProductCollection; // 修改原始集合,视图会自动刷新排序后的显示 collection.RemoveAt(_originalIndex); collection.Insert(targetIndex, _draggedItem); dataGrid.SelectedItem = _draggedItem; _draggedItem = null; } }
3. 临时禁用视图排序(可选兜底方案)
若上述方法仍有冲突,可在拖拽过程中临时清空视图排序,拖拽结束后恢复:
private List<SortDescription> _savedSortDescriptions = new(); // 先在DataGrid排序事件中保存排序规则 private void DataGrid_Sorting(object sender, DataGridSortingEventArgs e) { var view = CollectionViewSource.GetDefaultView((sender as DataGrid).ItemsSource); _savedSortDescriptions.Clear(); foreach (var sort in view.SortDescriptions) { _savedSortDescriptions.Add(new SortDescription(sort.PropertyName, sort.Direction)); } } // 拖拽时临时禁用排序 private void DataGrid_PreviewMouseMove(object sender, MouseEventArgs e) { if (_draggedItem != null && e.LeftButton == MouseButtonState.Pressed) { var dataGrid = sender as DataGrid; var view = CollectionViewSource.GetDefaultView(dataGrid.ItemsSource); view.SortDescriptions.Clear(); DragDrop.DoDragDrop(dataGrid, _draggedItem, DragDropEffects.Move); // 拖拽结束后恢复原有排序 foreach (var sort in _savedSortDescriptions) { view.SortDescriptions.Add(sort); } } }
4. 确保集合类接口合规
确认ProductCollection继承自ObservableCollection<Product>,该类已实现INotifyCollectionChanged和IList接口,能保证集合修改后视图自动同步:
public class ProductCollection : ObservableCollection<Product> { // 保留原有业务逻辑即可 }
核心思路
让拖拽操作直接作用于原始数据集合,而非DataGrid的排序视图。ICollectionView会自动将原始集合的修改同步到排序后的显示界面,实现排序状态与拖拽功能的共存。
内容的提问来源于stack exchange,提问作者Tech_T
相关产品推荐
相关产品推荐

