diff --git a/src/AtomUI.Controls.DataGrid/Column/DataGridRowReorderColumn.cs b/src/AtomUI.Controls.DataGrid/Column/DataGridRowReorderColumn.cs index a0964cf93..e5fc01753 100644 --- a/src/AtomUI.Controls.DataGrid/Column/DataGridRowReorderColumn.cs +++ b/src/AtomUI.Controls.DataGrid/Column/DataGridRowReorderColumn.cs @@ -1,7 +1,6 @@ using System.Collections; using System.Collections.Specialized; using System.Diagnostics; -using AtomUI.Controls.Data; using Avalonia; using Avalonia.Controls; using Avalonia.Input; @@ -121,6 +120,11 @@ public sealed class DataGridRowReorderColumn : DataGridColumn { throw DataGridError.DataGridRow.RowReorderNotAllowedException(); } + // TODO 需否需要检查每一列的配置 + if (owningGrid.CanUserFilterColumns || owningGrid.CanUserSortColumns) + { + throw DataGridError.DataGridRow.InvalidRowReorderPreConditionException(); + } owningGrid.PropertyChanged += HandleOwningGridItemsSourceChanged; } diff --git a/src/AtomUI.Controls.DataGrid/Column/DataGridRowReorderHandle.cs b/src/AtomUI.Controls.DataGrid/Column/DataGridRowReorderHandle.cs index ddd6cb864..3d4721659 100644 --- a/src/AtomUI.Controls.DataGrid/Column/DataGridRowReorderHandle.cs +++ b/src/AtomUI.Controls.DataGrid/Column/DataGridRowReorderHandle.cs @@ -6,7 +6,6 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Input; -using Avalonia.Threading; namespace AtomUI.Controls; @@ -26,9 +25,11 @@ internal class DataGridRowReorderHandle : TemplatedControl private static Point? _dragStart; private static double? _dragDelta; - private static DataGridRow? _dragRow; - private static DataGridRow? _prevDraggingOverRow; - private static DataGridRow? _currentDraggingOverRow; + + private static Rect? _dragRowBounds; + private static int? _dragRowIndex; + private static int? _currentDraggingOverRowIndex; + private static Point? _lastMousePositionInPresenter; private IconButton? _indicatorButton; @@ -67,48 +68,45 @@ internal class DataGridRowReorderHandle : TemplatedControl { _indicatorButton.DisableTransitions(); } - if (_prevDraggingOverRow != null && _prevDraggingOverRow != OwningRow) + if (_currentDraggingOverRowIndex != null && _currentDraggingOverRowIndex != _dragRowIndex) { if (OwningGrid.CollectionView is IList collectionView) { - var data = collectionView[OwningRow.Index]; - if (data is not null) + if (_dragRowIndex != null) { - collectionView.RemoveAt(OwningRow.Index); - collectionView.Insert(_prevDraggingOverRow.Index, data); + var data = collectionView[_dragRowIndex.Value]; + if (data is not null) + { + collectionView.RemoveAt(_dragRowIndex.Value); + collectionView.Insert(_currentDraggingOverRowIndex.Value, data); + } } + if (_indicatorButton != null) { _indicatorButton.EnableTransitions(); } - Dispatcher.UIThread.Post(() => - { - OwningGrid.CollectionView.Refresh(); - }); + OwningGrid.CollectionView.Refresh(); } } - OwningRow.Opacity = 1.0; - _dragDelta = null; - _dragRow = null; + _dragRowIndex = null; + _dragRowBounds = null; _dragStart = null; _lastMousePositionInPresenter = null; - _currentDraggingOverRow = null; - _prevDraggingOverRow = null; - rowsPresenter.DraggedRow = null; + _currentDraggingOverRowIndex = null; rowsPresenter.DragRowOffset = 0.0; + rowsPresenter.InvalidateArrange(); } private void HandlePointerMoved(object? sender, PointerEventArgs e) { - if (OwningGrid == null || !IsEnabled || OwningGrid.ColumnHeaders == null) + if (!e.GetCurrentPoint(this).Properties.IsLeftButtonPressed || OwningGrid == null || !IsEnabled || OwningGrid.ColumnHeaders == null) { return; } - Point mousePositionPresenter = e.GetPosition(OwningGrid.RowsPresenter); - Debug.Assert(OwningGrid.Parent is InputElement); HandleMouseMoveReorder(mousePositionPresenter); } @@ -122,38 +120,31 @@ internal class DataGridRowReorderHandle : TemplatedControl var rowsPresenter = OwningGrid.RowsPresenter; //handle entry into reorder mode - if (_dragRow == null && _lastMousePositionInPresenter != null) + if (_dragRowIndex == null && _lastMousePositionInPresenter != null) { HandleMouseMoveBeginReorder(mousePositionPresenter); } //handle reorder mode (eg, positioning of the popup) - if (rowsPresenter.DraggedRow != null) + if (rowsPresenter.DraggedRowIndex != null) { Debug.Assert(_dragStart != null); // Find row we're hovering over - var targetRow = GetReorderingTargetRow(mousePositionPresenter, true, out double scrollAmount); - if (targetRow != _currentDraggingOverRow) - { - _prevDraggingOverRow = _currentDraggingOverRow; - _currentDraggingOverRow = targetRow; - if (_currentDraggingOverRow != null && _currentDraggingOverRow != _dragRow) - { - rowsPresenter.SwapOrderingChildren(OwningRow, _currentDraggingOverRow); - } - } - + var targetRowIndex = GetReorderingTargetRow(mousePositionPresenter, true, out double scrollAmount); + _currentDraggingOverRowIndex = targetRowIndex; + if (_dragDelta == null) { - _dragDelta = _dragRow?.Bounds.Y; + _dragDelta = _dragRowBounds?.Y; } var delta = _dragDelta.HasValue ? _dragDelta.Value : 0.0; rowsPresenter.DragRowOffset = delta + mousePositionPresenter.Y - _dragStart.Value.Y + scrollAmount; + rowsPresenter.DraggedRowIndex = _dragRowIndex; rowsPresenter.InvalidateArrange(); } } - private DataGridRow? GetReorderingTargetRow(Point mousePositionPresenter, bool scroll, out double scrollAmount) + private int? GetReorderingTargetRow(Point mousePositionPresenter, bool scroll, out double scrollAmount) { scrollAmount = 0; Debug.Assert(OwningGrid != null); @@ -163,8 +154,8 @@ internal class DataGridRowReorderHandle : TemplatedControl var rowsPresenter = OwningGrid.RowsPresenter; - double topEdge = rowsPresenter.Bounds.Top; - double bottomEdge = rowsPresenter.Bounds.Bottom; + double topEdge = 0; + double bottomEdge = rowsPresenter.DesiredSize.Height; if (mousePositionPresenter.Y < topEdge) { @@ -187,23 +178,26 @@ internal class DataGridRowReorderHandle : TemplatedControl OwningGrid.VerticalScrollBar.IsVisible && OwningGrid.VerticalScrollBar.Value < OwningGrid.VerticalScrollBar.Maximum) { - double newVal = mousePositionPresenter.X - bottomEdge; + double newVal = mousePositionPresenter.Y - bottomEdge; scrollAmount = Math.Min(newVal, OwningGrid.VerticalScrollBar.Maximum - OwningGrid.VerticalScrollBar.Value); - OwningGrid.ScrollSlotsByHeight(scrollAmount); + if (scrollAmount > 0) + { + OwningGrid.ScrollSlotsByHeight(scrollAmount); + } } mousePositionPresenter = mousePositionPresenter.WithY(bottomEdge - 1); } - foreach (Control child in rowsPresenter.Children) + foreach (Control child in OwningGrid.DisplayData.GetScrollingElements()) { if (child is DataGridRow row) { Point mousePosition = OwningGrid.RowsPresenter.Translate(row, mousePositionPresenter); if (mousePosition.Y >= 0 && mousePosition.Y <= row.Bounds.Height) { - return row; + return row.Index; } } } @@ -225,13 +219,13 @@ internal class DataGridRowReorderHandle : TemplatedControl } // The user didn't cancel, so prepare for the reorder - _dragRow = OwningRow; - _dragStart = mousePosition; - _dragRow.Opacity = 0.0; + _dragRowIndex = OwningRow.Index; + _dragRowBounds = OwningRow.Bounds; + _dragStart = mousePosition; Debug.Assert(OwningGrid.RowsPresenter != null); // Display the reordering thumb - OwningGrid.RowsPresenter.DraggedRow = OwningRow; + OwningGrid.RowsPresenter.DraggedRowIndex = _dragRowIndex; OwningGrid.RowsPresenter.NotifyAboutToDragging(); } diff --git a/src/AtomUI.Controls.DataGrid/DataGrid.Privates.cs b/src/AtomUI.Controls.DataGrid/DataGrid.Privates.cs index 514b682dd..997bef015 100644 --- a/src/AtomUI.Controls.DataGrid/DataGrid.Privates.cs +++ b/src/AtomUI.Controls.DataGrid/DataGrid.Privates.cs @@ -3863,7 +3863,7 @@ public partial class DataGrid EditingRow = null; } - private void ResetFocusedRow() + internal void ResetFocusedRow() { if (_focusedRow != null && _focusedRow != EditingRow diff --git a/src/AtomUI.Controls.DataGrid/DataGridDisplayData.cs b/src/AtomUI.Controls.DataGrid/DataGridDisplayData.cs index 5b3d4bc6b..9cc797a81 100644 --- a/src/AtomUI.Controls.DataGrid/DataGridDisplayData.cs +++ b/src/AtomUI.Controls.DataGrid/DataGridDisplayData.cs @@ -161,16 +161,24 @@ internal class DataGridDisplayData { DataGridRow row = _recyclableRows.Pop(); row.IsVisible = false; - Debug.Assert(!_fullyRecycledRows.Contains(row)); - _fullyRecycledRows.Push(row); + // TODO 拖动的时候滚动翻页了会触发这个,暂时改成动态判断 + // Debug.Assert(!_fullyRecycledRows.Contains(row)); + if (!_fullyRecycledRows.Contains(row)) + { + _fullyRecycledRows.Push(row); + } } // Fully recycle Recyclable GroupHeaders and transfer them to Recycled GroupHeaders while (_recyclableGroupHeaders.Count > 0) { DataGridRowGroupHeader groupHeader = _recyclableGroupHeaders.Pop(); groupHeader.IsVisible = false; - Debug.Assert(!_fullyRecycledGroupHeaders.Contains(groupHeader)); - _fullyRecycledGroupHeaders.Push(groupHeader); + // TODO 拖动的时候滚动翻页了会触发这个,暂时改成动态判断 + // Debug.Assert(!_fullyRecycledGroupHeaders.Contains(groupHeader)); + if (!_fullyRecycledGroupHeaders.Contains(groupHeader)) + { + _fullyRecycledGroupHeaders.Push(groupHeader); + } } } diff --git a/src/AtomUI.Controls.DataGrid/DataGridError.cs b/src/AtomUI.Controls.DataGrid/DataGridError.cs index 541ad3f98..a3ea34253 100644 --- a/src/AtomUI.Controls.DataGrid/DataGridError.cs +++ b/src/AtomUI.Controls.DataGrid/DataGridError.cs @@ -122,14 +122,6 @@ internal static class DataGridError } - public static class DataGridColumnHeader - { - public static NotSupportedException ContentDoesNotSupportUIElements() - { - return new NotSupportedException("Content does not support Controls; use ContentTemplate instead."); - } - } - public static class DataGridColumn { public static NotSupportedException SelectionModeException() @@ -190,6 +182,11 @@ internal static class DataGridError { return new InvalidOperationException("Only one DataGridRowReorderColumn is allowed."); } + + public static InvalidOperationException InvalidRowReorderPreConditionException() + { + return new InvalidOperationException("Cannot start sorting or filtering while sorting is in progress."); + } } public static class DataGridSelectedItemsCollection diff --git a/src/AtomUI.Controls.DataGrid/Row/DataGridRowsPresenter.cs b/src/AtomUI.Controls.DataGrid/Row/DataGridRowsPresenter.cs index 9da154b5b..269239847 100644 --- a/src/AtomUI.Controls.DataGrid/Row/DataGridRowsPresenter.cs +++ b/src/AtomUI.Controls.DataGrid/Row/DataGridRowsPresenter.cs @@ -4,6 +4,7 @@ // All other rights reserved. using System.Diagnostics; +using AtomUI.Controls.Data; using AtomUI.Utils; using Avalonia; using Avalonia.Controls; @@ -21,9 +22,9 @@ namespace AtomUI.Controls; public sealed class DataGridRowsPresenter : Panel, IChildIndexProvider { #region 内部属性定义 - - internal DataGridRow? DraggedRow { get; set; } - + + internal int? DraggedRowIndex { get; set; } + internal Double DragRowOffset { get; set; } internal DataGrid? OwningGrid { get; set; } @@ -31,7 +32,6 @@ public sealed class DataGridRowsPresenter : Panel, IChildIndexProvider #endregion - private List? _orderingChildren; private DataGridRow? _dragIndicator; public DataGridRowsPresenter() @@ -89,7 +89,16 @@ public sealed class DataGridRowsPresenter : Panel, IChildIndexProvider double rowDesiredWidth = OwningGrid.RowHeadersDesiredWidth + OwningGrid.ColumnsInternal.VisibleEdgedColumnsWidth + OwningGrid.ColumnsInternal.FillerColumn.FillerWidth; double topEdge = -OwningGrid.NegVerticalOffset; - foreach (Control element in GetScrollingElements()) + + var visibleRows = new List(); + visibleRows.AddRange(OwningGrid.DisplayData.GetScrollingElements()); + + if (_dragIndicator != null) + { + visibleRows.Add(_dragIndicator); + } + + foreach (Control element in visibleRows) { if (element is DataGridRow row) { @@ -98,15 +107,14 @@ public sealed class DataGridRowsPresenter : Panel, IChildIndexProvider // Visibility for all filler cells needs to be set in one place. Setting it individually in // each CellsPresenter causes an NxN layout cycle (see DevDiv Bugs 211557) row.EnsureFillerVisibility(); - if (_dragIndicator != row) - { - row.Arrange(new Rect(0, topEdge, rowDesiredWidth, element.DesiredSize.Height)); - } - else + if (_dragIndicator == row) { row.Arrange(new Rect(0, DragRowOffset, rowDesiredWidth, element.DesiredSize.Height)); } - + else + { + row.Arrange(new Rect(0, topEdge, rowDesiredWidth, element.DesiredSize.Height)); + } } else if (element is DataGridRowGroupHeader groupHeader) { @@ -172,7 +180,14 @@ public sealed class DataGridRowsPresenter : Panel, IChildIndexProvider double totalCellsWidth = OwningGrid.ColumnsInternal.VisibleEdgedColumnsWidth; double headerWidth = 0; - foreach (Control element in GetScrollingElements()) + + var visibleRows = OwningGrid.DisplayData.GetScrollingElements().ToList(); + if (_dragIndicator != null) + { + visibleRows.Add(_dragIndicator); + } + + foreach (Control element in visibleRows) { DataGridRow? row = element as DataGridRow; if (row != null) @@ -213,37 +228,25 @@ public sealed class DataGridRowsPresenter : Panel, IChildIndexProvider { e.Handled = e.Handled || (OwningGrid?.UpdateScroll(-e.Delta) ?? false); } - - IEnumerable GetScrollingElements() - { - Debug.Assert(OwningGrid != null); - if (DraggedRow != null) - { - return _orderingChildren!; - } - - return OwningGrid.DisplayData.GetScrollingElements(); - } internal void NotifyAboutToDragging() { Debug.Assert(OwningGrid != null); - Debug.Assert(DraggedRow != null); - _orderingChildren = new List(); - _orderingChildren.AddRange(OwningGrid.DisplayData.GetScrollingElements()); - _dragIndicator = OwningGrid.GetGeneratedGhostRow(DraggedRow.DataContext); - _dragIndicator.Index = DraggedRow.Index; + Debug.Assert(DraggedRowIndex.HasValue); + object? data = null; + if (OwningGrid.CollectionView is DataGridCollectionView collectionView) + { + data = collectionView.GetItemAt(DraggedRowIndex.Value); + } + _dragIndicator = OwningGrid.GetGeneratedGhostRow(data); + _dragIndicator.Index = DraggedRowIndex.Value; _dragIndicator.IsDragging = true; - _dragIndicator.ZIndex = 1000; - _orderingChildren.Add(_dragIndicator); LogicalChildren.Add(_dragIndicator); VisualChildren.Add(_dragIndicator); } internal void NotifyDropped() { - _orderingChildren?.Clear(); - _orderingChildren = null; if (_dragIndicator != null) { LogicalChildren.Remove(_dragIndicator); @@ -253,25 +256,6 @@ public sealed class DataGridRowsPresenter : Panel, IChildIndexProvider _dragIndicator = null; } - public void SwapOrderingChildren(Control item1, Control item2) - { - if (_orderingChildren != null) - { - if (!_orderingChildren.Contains(item1)) - { - throw new ArgumentOutOfRangeException(nameof(item1)); - } - - if (!_orderingChildren.Contains(item2)) - { - throw new ArgumentOutOfRangeException(nameof(item2)); - } - var index1 = _orderingChildren.IndexOf(item1); - var index2 = _orderingChildren.IndexOf(item2); - (_orderingChildren[index2], _orderingChildren[index1]) = (_orderingChildren[index1], _orderingChildren[index2]); - } - } - #if DEBUG internal void PrintChildren() { diff --git a/src/AtomUI.Controls.DataGrid/Themes/DataGridRowTheme.axaml b/src/AtomUI.Controls.DataGrid/Themes/DataGridRowTheme.axaml index c3aa7dcc0..fff37051a 100644 --- a/src/AtomUI.Controls.DataGrid/Themes/DataGridRowTheme.axaml +++ b/src/AtomUI.Controls.DataGrid/Themes/DataGridRowTheme.axaml @@ -62,6 +62,7 @@ +