From f7573fcbc705d7f998f3ade282f2f481d590dc5a Mon Sep 17 00:00:00 2001 From: chinboy Date: Mon, 14 Jul 2025 22:02:28 +0800 Subject: [PATCH] Add DataGrid Column reorder --- .../Column/DataGridColumnHeader.cs | 9 +- .../Column/DataGridDraggingOverIndicator.cs | 87 +++++++++++++++++++ .../DataGrid.Columns.cs | 17 ++++ .../DataGrid.Privates.cs | 2 +- src/AtomUI.Controls.DataGrid/DataGrid.cs | 2 +- .../Themes/DataGridTheme.axaml | 8 ++ .../Themes/DataGridThemeConstants.cs | 1 + 7 files changed, 117 insertions(+), 9 deletions(-) create mode 100644 src/AtomUI.Controls.DataGrid/Column/DataGridDraggingOverIndicator.cs diff --git a/src/AtomUI.Controls.DataGrid/Column/DataGridColumnHeader.cs b/src/AtomUI.Controls.DataGrid/Column/DataGridColumnHeader.cs index 94edf1675..3287d3bdf 100644 --- a/src/AtomUI.Controls.DataGrid/Column/DataGridColumnHeader.cs +++ b/src/AtomUI.Controls.DataGrid/Column/DataGridColumnHeader.cs @@ -613,15 +613,10 @@ internal partial class DataGridColumnHeader : ContentControl foreach (DataGridColumn column in OwningGrid.ColumnsInternal.GetVisibleColumns()) { Point mousePosition = OwningGrid.ColumnHeaders.Translate(column.HeaderCell, mousePositionHeaders); - double columnMiddle = column.HeaderCell.Bounds.Width / 2; - if (mousePosition.X >= 0 && mousePosition.X <= columnMiddle) + if (mousePosition.X >= 0 && mousePosition.X <= column.HeaderCell.Bounds.Width) { return column; } - if (mousePosition.X > columnMiddle && mousePosition.X < column.HeaderCell.Bounds.Width) - { - return OwningGrid.ColumnsInternal.GetNextVisibleColumn(column); - } } return null; @@ -639,7 +634,7 @@ internal partial class DataGridColumnHeader : ContentControl DataGridColumn? targetColumn = GetReorderingTargetColumn(mousePositionHeaders, false /*scroll*/, out double scrollAmount); if (targetColumn != null) { - return targetColumn.DisplayIndex > OwningColumn.DisplayIndex ? targetColumn.DisplayIndex - 1 : targetColumn.DisplayIndex; + return targetColumn.DisplayIndex; } return OwningGrid.Columns.Count - 1; } diff --git a/src/AtomUI.Controls.DataGrid/Column/DataGridDraggingOverIndicator.cs b/src/AtomUI.Controls.DataGrid/Column/DataGridDraggingOverIndicator.cs new file mode 100644 index 000000000..eb5fea120 --- /dev/null +++ b/src/AtomUI.Controls.DataGrid/Column/DataGridDraggingOverIndicator.cs @@ -0,0 +1,87 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Documents; +using Avalonia.Media; + +namespace AtomUI.Controls; + +internal class DataGridDraggingOverIndicator : Control +{ + internal static readonly DirectProperty DraggingOverColumnProperty = + AvaloniaProperty.RegisterDirect( + nameof(DraggingOverColumn), + o => o.DraggingOverColumn, + (o, v) => o.DraggingOverColumn = v); + + internal static readonly DirectProperty DraggedColumnProperty = + AvaloniaProperty.RegisterDirect( + nameof(DraggedColumn), + o => o.DraggedColumn, + (o, v) => o.DraggedColumn = v); + + internal DataGridColumn? DraggingOverColumn + { + get => _draggingOverColumn; + set => SetAndRaise(DraggingOverColumnProperty, ref _draggingOverColumn, value); + } + private DataGridColumn? _draggingOverColumn; + + internal DataGridColumn? DraggedColumn + { + get => _draggedColumn; + set => SetAndRaise(DraggedColumnProperty, ref _draggedColumn, value); + } + private DataGridColumn? _draggedColumn; + + static DataGridDraggingOverIndicator() + { + AffectsRender(DraggingOverColumnProperty, DraggedColumnProperty); + } + + private double _indicatorOffsetX; + private double _indicatorLineWidth = 1.0; + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + if (change.Property == DraggingOverColumnProperty || + change.Property == DraggedColumnProperty) + { + CalculateIndicatorOffset(); + } + } + + private void CalculateIndicatorOffset() + { + if (DraggingOverColumn != null && DraggedColumn != null) + { + var offset = DraggingOverColumn.HeaderCell.TranslatePoint(new Point(0, 0), this); + if (offset.HasValue) + { + var headerSize = DraggingOverColumn.HeaderCell.Bounds.Size; + if (DraggedColumn.DisplayIndex < DraggingOverColumn.DisplayIndex) + { + _indicatorOffsetX = offset.Value.X + headerSize.Width; + } + else + { + _indicatorOffsetX = offset.Value.X; + } + } + } + } + + public override void Render(DrawingContext context) + { + if (DraggingOverColumn != null) + { + using var state = context.PushRenderOptions(new RenderOptions + { + EdgeMode = EdgeMode.Aliased + }); + var startPoint = new Point(_indicatorOffsetX, 0); + var endPoint = new Point(_indicatorOffsetX, Bounds.Height); + context.DrawLine(new Pen(TextElement.GetForeground(this), _indicatorLineWidth, DashStyle.Dash), startPoint, endPoint); + } + } +} \ No newline at end of file diff --git a/src/AtomUI.Controls.DataGrid/DataGrid.Columns.cs b/src/AtomUI.Controls.DataGrid/DataGrid.Columns.cs index 006335ef1..c7e5ce89b 100644 --- a/src/AtomUI.Controls.DataGrid/DataGrid.Columns.cs +++ b/src/AtomUI.Controls.DataGrid/DataGrid.Columns.cs @@ -105,6 +105,7 @@ public partial class DataGrid private DataGridColumnHeadersPresenter? _columnHeadersPresenter; private DataGridGroupColumnHeadersPresenter? _groupColumnHeadersPresenter; + private DataGridDraggingOverIndicator? _dataGridDraggingOverIndicator; protected virtual void NotifyColumnDisplayIndexChanged(DataGridColumnEventArgs e) { @@ -124,6 +125,22 @@ public partial class DataGrid protected internal virtual void NotifyColumnDraggingOver(DataGridColumnDraggingOverEventArgs e) { + if (_dataGridDraggingOverIndicator != null) + { + if (e.DraggedColumn != null && e.DraggingOverColumn != null && e.DraggedColumn != e.DraggingOverColumn) + { + _dataGridDraggingOverIndicator.IsVisible = true; + _dataGridDraggingOverIndicator.DraggingOverColumn = e.DraggingOverColumn; + _dataGridDraggingOverIndicator.DraggedColumn = e.DraggedColumn; + } + else + { + _dataGridDraggingOverIndicator.IsVisible = false; + _dataGridDraggingOverIndicator.DraggingOverColumn = null; + _dataGridDraggingOverIndicator.DraggedColumn = null; + } + } + ColumnDraggingOver?.Invoke(this, e); } diff --git a/src/AtomUI.Controls.DataGrid/DataGrid.Privates.cs b/src/AtomUI.Controls.DataGrid/DataGrid.Privates.cs index 2371df053..e4a87ae29 100644 --- a/src/AtomUI.Controls.DataGrid/DataGrid.Privates.cs +++ b/src/AtomUI.Controls.DataGrid/DataGrid.Privates.cs @@ -11,7 +11,6 @@ using System.Diagnostics; using System.Reactive.Disposables; using AtomUI.Controls.Data; using AtomUI.Controls.Utils; -using AtomUI.Data; using AtomUI.Theme; using AtomUI.Utils; using Avalonia; @@ -32,6 +31,7 @@ public partial class DataGrid internal const bool DefaultCanUserSortColumns = false; internal const bool DefaultCanUserFilterColumns = false; internal const bool DefaultShowSorterTooltip = false; + internal const int DraggingOverIndicatorZIndex = 1000; #region 内部属性定义 diff --git a/src/AtomUI.Controls.DataGrid/DataGrid.cs b/src/AtomUI.Controls.DataGrid/DataGrid.cs index 66a4f311c..38b7fada7 100644 --- a/src/AtomUI.Controls.DataGrid/DataGrid.cs +++ b/src/AtomUI.Controls.DataGrid/DataGrid.cs @@ -1404,7 +1404,7 @@ public partial class DataGrid : TemplatedControl, _columnHeadersPresenter = e.NameScope.Find(DataGridThemeConstants.ColumnHeadersPresenterPart); _groupColumnHeadersPresenter = e.NameScope.Find(DataGridThemeConstants.GroupColumnHeadersPresenterPart); - + _dataGridDraggingOverIndicator = e.NameScope.Find(DataGridThemeConstants.DraggingOverIndicatorPart); if (_groupColumnHeadersPresenter != null) { _groupColumnHeadersPresenter.OwningGrid = this; diff --git a/src/AtomUI.Controls.DataGrid/Themes/DataGridTheme.axaml b/src/AtomUI.Controls.DataGrid/Themes/DataGridTheme.axaml index 61dd573f9..b6517f200 100644 --- a/src/AtomUI.Controls.DataGrid/Themes/DataGridTheme.axaml +++ b/src/AtomUI.Controls.DataGrid/Themes/DataGridTheme.axaml @@ -103,6 +103,14 @@ VerticalAlignment="Stretch" CornerRadius="{TemplateBinding HeaderCornerRadius}" IsEnabled="{TemplateBinding IsEnabled}" /> + + diff --git a/src/AtomUI.Controls.DataGrid/Themes/DataGridThemeConstants.cs b/src/AtomUI.Controls.DataGrid/Themes/DataGridThemeConstants.cs index 5d1054e8d..95b88d905 100644 --- a/src/AtomUI.Controls.DataGrid/Themes/DataGridThemeConstants.cs +++ b/src/AtomUI.Controls.DataGrid/Themes/DataGridThemeConstants.cs @@ -102,6 +102,7 @@ internal static class DataGridThemeConstants public const string DisabledVisualElementPart = "PART_DisabledVisualElement"; public const string TitlePart = "PART_Title"; public const string FooterPart = "PART_Footer"; + public const string DraggingOverIndicatorPart = "PART_DraggingOverIndicator"; } internal static class DataGridTopLeftColumnHeaderThemeConstants