From 6992bd72ceabe81dc58f0af82186e53c1575dd2d Mon Sep 17 00:00:00 2001 From: Maksym Katsydan Date: Thu, 17 Sep 2020 00:37:56 -0400 Subject: [PATCH] Add Sorting event and use ListSortDirection instead of bool property --- .../Collections/DataGridSortDescription.cs | 42 +++++--- src/Avalonia.Controls.DataGrid/DataGrid.cs | 5 + .../DataGridColumn.cs | 2 +- .../DataGridColumnHeader.cs | 97 ++++++++++--------- .../DataGridColumns.cs | 5 + src/Avalonia.Controls.DataGrid/EventArgs.cs | 4 +- 6 files changed, 91 insertions(+), 64 deletions(-) diff --git a/src/Avalonia.Controls.DataGrid/Collections/DataGridSortDescription.cs b/src/Avalonia.Controls.DataGrid/Collections/DataGridSortDescription.cs index f741d40571..ffb36d187d 100644 --- a/src/Avalonia.Controls.DataGrid/Collections/DataGridSortDescription.cs +++ b/src/Avalonia.Controls.DataGrid/Collections/DataGridSortDescription.cs @@ -1,19 +1,21 @@ using System; using System.Collections; using System.Collections.Generic; +using System.ComponentModel; using System.Globalization; using System.Linq; -using System.Text; -using Avalonia.Controls; using Avalonia.Controls.Utils; -using Avalonia.Utilities; namespace Avalonia.Collections { public abstract class DataGridSortDescription { public virtual string PropertyPath => null; - public virtual bool Descending => false; + + [Obsolete("Use Direction property to read or override sorting direction.")] + public virtual bool Descending => Direction == ListSortDirection.Descending; + + public virtual ListSortDirection Direction => ListSortDirection.Ascending; public bool HasPropertyPath => !String.IsNullOrEmpty(PropertyPath); public abstract IComparer Comparer { get; } @@ -105,7 +107,7 @@ namespace Avalonia.Collections private class DataGridPathSortDescription : DataGridSortDescription { - private readonly bool _descending; + private readonly ListSortDirection _direction; private readonly string _propertyPath; private readonly Lazy _cultureSensitiveComparer; private readonly Lazy> _comparer; @@ -130,19 +132,19 @@ namespace Avalonia.Collections public override string PropertyPath => _propertyPath; public override IComparer Comparer => _comparer.Value; - public override bool Descending => _descending; + public override ListSortDirection Direction => _direction; - public DataGridPathSortDescription(string propertyPath, bool descending, CultureInfo culture) + public DataGridPathSortDescription(string propertyPath, ListSortDirection direction, CultureInfo culture) { _propertyPath = propertyPath; - _descending = descending; + _direction = direction; _cultureSensitiveComparer = new Lazy(() => new CultureSensitiveComparer(culture ?? CultureInfo.CurrentCulture)); _comparer = new Lazy>(() => Comparer.Create((x, y) => Compare(x, y))); } - private DataGridPathSortDescription(DataGridPathSortDescription inner, bool descending) + private DataGridPathSortDescription(DataGridPathSortDescription inner, ListSortDirection direction) { _propertyPath = inner._propertyPath; - _descending = descending; + _direction = direction; _propertyType = inner._propertyType; _cultureSensitiveComparer = inner._cultureSensitiveComparer; _internalComparer = inner._internalComparer; @@ -201,7 +203,7 @@ namespace Avalonia.Collections result = _internalComparer?.Compare(v1, v2) ?? 0; - if (_descending) + if (Direction == ListSortDirection.Descending) return -result; else return result; @@ -218,7 +220,7 @@ namespace Avalonia.Collections } public override IOrderedEnumerable OrderBy(IEnumerable seq) { - if(_descending) + if (Direction == ListSortDirection.Descending) { return seq.OrderByDescending(o => GetValue(o), InternalComparer); } @@ -229,7 +231,7 @@ namespace Avalonia.Collections } public override IOrderedEnumerable ThenBy(IOrderedEnumerable seq) { - if (_descending) + if (Direction == ListSortDirection.Descending) { return seq.ThenByDescending(o => GetValue(o), InternalComparer); } @@ -241,13 +243,21 @@ namespace Avalonia.Collections internal override DataGridSortDescription SwitchSortDirection() { - return new DataGridPathSortDescription(this, !_descending); + var newDirection = _direction == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending; + return new DataGridPathSortDescription(this, newDirection); } } - public static DataGridSortDescription FromPath(string propertyPath, bool descending = false, CultureInfo culture = null) + public static DataGridSortDescription FromPath(string propertyPath, ListSortDirection direction = ListSortDirection.Ascending, CultureInfo culture = null) + { + return new DataGridPathSortDescription(propertyPath, direction, culture); + } + + + [Obsolete("Use overload taking a ListSortDirection.")] + public static DataGridSortDescription FromPath(string propertyPath, bool descending, CultureInfo culture = null) { - return new DataGridPathSortDescription(propertyPath, descending, culture); + return new DataGridPathSortDescription(propertyPath, descending ? ListSortDirection.Descending : ListSortDirection.Ascending, culture); } } diff --git a/src/Avalonia.Controls.DataGrid/DataGrid.cs b/src/Avalonia.Controls.DataGrid/DataGrid.cs index f7903086ab..9ca0b91523 100644 --- a/src/Avalonia.Controls.DataGrid/DataGrid.cs +++ b/src/Avalonia.Controls.DataGrid/DataGrid.cs @@ -1229,6 +1229,11 @@ namespace Avalonia.Controls remove { AddHandler(SelectionChangedEvent, value); } } + /// + /// Occurs when the sorting request is triggered. + /// + public event EventHandler Sorting; + /// /// Occurs when a /// object becomes available for reuse. diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridColumn.cs index 128fbde0c1..23c4acdf6c 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridColumn.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridColumn.cs @@ -1047,4 +1047,4 @@ namespace Avalonia.Controls } -} \ No newline at end of file +} diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs b/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs index 017718bc92..25aae99942 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs @@ -161,13 +161,14 @@ namespace Avalonia.Controls var sort = OwningColumn.GetSortDescription(); if (sort != null) { - CurrentSortingState = sort.Descending ? ListSortDirection.Descending : ListSortDirection.Ascending; + CurrentSortingState = sort.Direction; } } + PseudoClasses.Set(":sortascending", - CurrentSortingState.HasValue && CurrentSortingState.Value == ListSortDirection.Ascending); + CurrentSortingState == ListSortDirection.Ascending); PseudoClasses.Set(":sortdescending", - CurrentSortingState.HasValue && CurrentSortingState.Value == ListSortDirection.Descending); + CurrentSortingState == ListSortDirection.Descending); } internal void UpdateSeparatorVisibility(DataGridColumn lastVisibleColumn) @@ -215,70 +216,76 @@ namespace Avalonia.Controls internal void ProcessSort(KeyModifiers keyModifiers) { // if we can sort: - // - DataConnection.AllowSort is true, and // - AllowUserToSortColumns and CanSort are true, and - // - OwningColumn is bound, and - // - SortDescriptionsCollection exists, and - // - the column's data type is comparable + // - OwningColumn is bound // then try to sort if (OwningColumn != null && OwningGrid != null && OwningGrid.EditingRow == null && OwningColumn != OwningGrid.ColumnsInternal.FillerColumn - && OwningGrid.DataConnection.AllowSort && OwningGrid.CanUserSortColumns - && OwningColumn.CanUserSort - && OwningGrid.DataConnection.SortDescriptions != null) + && OwningColumn.CanUserSort) { - DataGrid owningGrid = OwningGrid; + var ea = new DataGridColumnEventArgs(OwningColumn); + OwningGrid.OnColumnSorting(ea); - DataGridSortDescription newSort; + if (!ea.Handled && OwningGrid.DataConnection.AllowSort && OwningGrid.DataConnection.SortDescriptions != null) + { + // - DataConnection.AllowSort is true, and + // - SortDescriptionsCollection exists, and + // - the column's data type is comparable - KeyboardHelper.GetMetaKeyState(keyModifiers, out bool ctrl, out bool shift); + DataGrid owningGrid = OwningGrid; + DataGridSortDescription newSort; - DataGridSortDescription sort = OwningColumn.GetSortDescription(); - IDataGridCollectionView collectionView = owningGrid.DataConnection.CollectionView; - Debug.Assert(collectionView != null); - using (collectionView.DeferRefresh()) - { - // if shift is held down, we multi-sort, therefore if it isn't, we'll clear the sorts beforehand - if (!shift || owningGrid.DataConnection.SortDescriptions.Count == 0) - { - owningGrid.DataConnection.SortDescriptions.Clear(); - } + KeyboardHelper.GetMetaKeyState(keyModifiers, out bool ctrl, out bool shift); + + DataGridSortDescription sort = OwningColumn.GetSortDescription(); + IDataGridCollectionView collectionView = owningGrid.DataConnection.CollectionView; + Debug.Assert(collectionView != null); - // if ctrl is held down, we only clear the sort directions - if (!ctrl) + using (collectionView.DeferRefresh()) { - if (sort != null) + // if shift is held down, we multi-sort, therefore if it isn't, we'll clear the sorts beforehand + if (!shift || owningGrid.DataConnection.SortDescriptions.Count == 0) { - newSort = sort.SwitchSortDirection(); + owningGrid.DataConnection.SortDescriptions.Clear(); + } - // changing direction should not affect sort order, so we replace this column's - // sort description instead of just adding it to the end of the collection - int oldIndex = owningGrid.DataConnection.SortDescriptions.IndexOf(sort); - if (oldIndex >= 0) + // if ctrl is held down, we only clear the sort directions + if (!ctrl) + { + if (sort != null) { - owningGrid.DataConnection.SortDescriptions.Remove(sort); - owningGrid.DataConnection.SortDescriptions.Insert(oldIndex, newSort); + newSort = sort.SwitchSortDirection(); + + // changing direction should not affect sort order, so we replace this column's + // sort description instead of just adding it to the end of the collection + int oldIndex = owningGrid.DataConnection.SortDescriptions.IndexOf(sort); + if (oldIndex >= 0) + { + owningGrid.DataConnection.SortDescriptions.Remove(sort); + owningGrid.DataConnection.SortDescriptions.Insert(oldIndex, newSort); + } + else + { + owningGrid.DataConnection.SortDescriptions.Add(newSort); + } } else { + string propertyName = OwningColumn.GetSortPropertyName(); + // no-opt if we couldn't find a property to sort on + if (string.IsNullOrEmpty(propertyName)) + { + return; + } + + newSort = DataGridSortDescription.FromPath(propertyName, culture: collectionView.Culture); + owningGrid.DataConnection.SortDescriptions.Add(newSort); } } - else - { - string propertyName = OwningColumn.GetSortPropertyName(); - // no-opt if we couldn't find a property to sort on - if (string.IsNullOrEmpty(propertyName)) - { - return; - } - - newSort = DataGridSortDescription.FromPath(propertyName, culture: collectionView.Culture); - owningGrid.DataConnection.SortDescriptions.Add(newSort); - } } } } diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumns.cs b/src/Avalonia.Controls.DataGrid/DataGridColumns.cs index 5b75bc73f9..46bcd0d347 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridColumns.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridColumns.cs @@ -33,6 +33,11 @@ namespace Avalonia.Controls ColumnReordering?.Invoke(this, e); } + protected internal virtual void OnColumnSorting(DataGridColumnEventArgs e) + { + Sorting?.Invoke(this, e); + } + /// /// Adjusts the widths of all columns with DisplayIndex >= displayIndex such that the total /// width is adjusted by the given amount, if possible. If the total desired adjustment amount diff --git a/src/Avalonia.Controls.DataGrid/EventArgs.cs b/src/Avalonia.Controls.DataGrid/EventArgs.cs index 10e2be795e..7590a8ed61 100644 --- a/src/Avalonia.Controls.DataGrid/EventArgs.cs +++ b/src/Avalonia.Controls.DataGrid/EventArgs.cs @@ -289,7 +289,7 @@ namespace Avalonia.Controls /// /// Provides data for column-related events. /// - public class DataGridColumnEventArgs : EventArgs + public class DataGridColumnEventArgs : HandledEventArgs { /// /// Initializes a new instance of the class. @@ -566,4 +566,4 @@ namespace Avalonia.Controls private set; } } -} \ No newline at end of file +}