Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ private void Setup()
// right list
AdvancedCollectionView acv = new(EmployeeCollection);
acv.Filter = x => !int.TryParse(((Employee)x).Name, out _);
acv.SortDescriptions.Add(new(nameof(Employee.Name), SortDirection.Ascending));
acv.SortDescriptions.Add(new SortDescription<Employee>(nameof(Employee.Name), SortDirection.Ascending));

CollectionView = acv;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ namespace CommunityToolkit.WinUI.Collections;
/// <summary>
/// A collection view implementation that supports filtering, sorting and incremental loading
/// </summary>
#if NET8_0_OR_GREATER
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Item sorting uses reflection to get property types and may not be AOT compatible.")]
#endif
public partial class AdvancedCollectionView : IAdvancedCollectionView, INotifyPropertyChanged, ISupportIncrementalLoading, IComparer<object>
{
private readonly List<object> _view;
Expand Down Expand Up @@ -383,7 +380,7 @@ public Predicate<object> Filter
int IComparer<object>.Compare(object x, object y)
#pragma warning restore CA1033 // Interface methods should be callable by child types
{
if (!_sortProperties.Any())
if (_sortProperties.Count == 0)
{
var listType = _source?.GetType();
Type type;
Expand All @@ -401,7 +398,7 @@ int IComparer<object>.Compare(object x, object y)
{
if (!string.IsNullOrEmpty(sd.PropertyName))
{
_sortProperties[sd.PropertyName] = type.GetProperty(sd.PropertyName);
_sortProperties[sd.PropertyName] = sd.GetProperty(type);
}
}
}
Expand All @@ -419,8 +416,8 @@ int IComparer<object>.Compare(object x, object y)
{
var pi = _sortProperties[sd.PropertyName];

cx = pi.GetValue(x!);
cy = pi.GetValue(y!);
cx = pi.GetValue(x);
cy = pi.GetValue(y);
}

var cmp = sd.Comparer.Compare(cx, cy);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.

using System.Collections;
using System.Diagnostics.CodeAnalysis;

namespace CommunityToolkit.WinUI.Collections;

Expand All @@ -14,7 +15,7 @@ public class SortDescription
/// <summary>
/// Gets the name of property to sort on
/// </summary>
public string PropertyName { get; }
public virtual string? PropertyName { get; }
Comment thread
sylveon marked this conversation as resolved.
Outdated

/// <summary>
/// Gets the direction of sort
Expand All @@ -33,8 +34,10 @@ public class SortDescription
/// <param name="direction">Direction of sort</param>
/// <param name="comparer">Comparer to use. If null, will use default comparer</param>
public SortDescription(SortDirection direction, IComparer? comparer = null)
: this(null!, direction, comparer!)
{
PropertyName = null;
Direction = direction;
Comparer = comparer ?? ObjectComparer.Instance;
}

/// <summary>
Expand All @@ -43,13 +46,22 @@ public SortDescription(SortDirection direction, IComparer? comparer = null)
/// <param name="propertyName">Name of property to sort on</param>
/// <param name="direction">Direction of sort</param>
/// <param name="comparer">Comparer to use. If null, will use default comparer</param>
#if NET5_0_OR_GREATER
[RequiresUnreferencedCode("Item sorting with the property name uses reflection to get the property and is not trim-safe. Either use SortDescription<T> to preserve the required metadata, or use the other constructor without a property name.")]
#endif
public SortDescription(string propertyName, SortDirection direction, IComparer? comparer = null)
{
PropertyName = propertyName;
Direction = direction;
Comparer = comparer ?? ObjectComparer.Instance;
}


Comment thread
sylveon marked this conversation as resolved.
[UnconditionalSuppressMessage("Trimming", "IL2070:'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The parameter of method does not have matching annotations.",
Comment thread
sylveon marked this conversation as resolved.
Justification = "The path which does reflection is only triggered if the user uses the constructor with RequiresUnreferencedCode (which bubbles the warning to them)")]
internal virtual PropertyInfo? GetProperty(Type type)
=> PropertyName != null ? type.GetProperty(PropertyName) : null;

private class ObjectComparer : IComparer
{
public static readonly IComparer Instance = new ObjectComparer();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections;
using System.Diagnostics.CodeAnalysis;

namespace CommunityToolkit.WinUI.Collections;

/// <summary>
/// A generic version of <see cref="SortDescription"/> which preserves the required metadata for reflection-based sorting.
/// </summary>
/// <typeparam name="T">The type to sort</typeparam>
public class SortDescription<
Comment thread
sylveon marked this conversation as resolved.
Outdated
#if NET5_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
#endif
T> : SortDescription
{
private readonly PropertyInfo _prop;

/// <inheritdoc/>
public override string PropertyName => _prop.Name;

/// <summary>
/// Initializes a new instance of the <see cref="SortDescription{T}"/> class.
/// </summary>
/// <param name="propertyName">Name of property to sort on</param>
/// <param name="direction">Direction of sort</param>
/// <param name="comparer">Comparer to use. If null, will use default comparer</param>
public SortDescription(string propertyName, SortDirection direction, IComparer? comparer = null) : base(direction, comparer)
{
_prop = typeof(T).GetProperty(propertyName) ?? throw new ArgumentException("Type does not have the expected property");
}

internal override PropertyInfo? GetProperty(Type type) =>
type.IsAssignableTo(_prop.DeclaringType) ? _prop : throw new ArgumentException("This SortDescription is not compatible with this type");
}