Description
Description
BindingSource.Sort fails with custom IBindingListView in .NET 9 (worked in .NET 8)
Reproduction Steps
Create a custom class implementing IBindingListView and IBindingList, inheriting from BindingList (see code in Other Information).
Set it as the DataSource of a BindingSource.
Set BindingSource.Sort = "Property desc" where Property exists in the item type.
Observe the result.
Expected behavior
In .NET 8, BindingSource.Sort calls IBindingList.ApplySort, sorting the list.
The list is sorted, and no exception is thrown.
Actual behavior
In .NET 9, it throws "Sort string contains a property that is not in the IBindingList" without calling IBindingList.ApplySort.
Regression?
It worked in .net8
Known Workarounds
In my actual application, I can sort the BindingListView before I pass it to the BindingSource and it works. Once the BindingSource is bound to the DataGridView, you can sort by clicking the column headers. I tried sorting the BindingSource after it was passed to the DataGridView and the Sort property still threw the above error. The problem seems to be with setting the Sort property of the BindingSource.
Configuration
.NET 9.0
Windows 11
x64
Other information
namespace WinFormsApp1
{
using System.ComponentModel;
using System.Windows.Forms;
public class Journal
{
public DateTime IDate { get; set; }
public string Name { get; set; }
}
public class SimpleBindingList<T> : BindingList<T>, IBindingListView
{
public SimpleBindingList(List<T> list) : base(list) { }
// IBindingListView members
public void ApplySort(ListSortDescriptionCollection sorts)
{
Console.WriteLine("IBindingListView.ApplySort called");
// Minimal implementation for multi-column sort
}
public string Filter { get => ""; set { } }
public void RemoveFilter() { }
public ListSortDescriptionCollection SortDescriptions => new ListSortDescriptionCollection();
public bool SupportsAdvancedSorting => true;
public bool SupportsFiltering => true;
// IBindingList overrides
protected override bool SupportsSortingCore => true;
protected override bool IsSortedCore => false;
protected override PropertyDescriptor SortPropertyCore => null;
protected override ListSortDirection SortDirectionCore => ListSortDirection.Ascending;
protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection dir)
{
Console.WriteLine($"ApplySortCore called with {prop?.Name} {dir}");
if (prop == null) throw new ArgumentNullException(nameof(prop));
// Minimal sort logic (not needed to repro the error)
List<T> list = Items as List<T>;
if (list != null)
{
list.Sort((x, y) => Comparer<object>.Create((a, b) => a.ToString().CompareTo(b.ToString()))
.Compare(prop.GetValue(x), prop.GetValue(y)));
}
}
// Explicit IBindingList implementation
void IBindingList.ApplySort(PropertyDescriptor property, ListSortDirection direction)
{
Console.WriteLine($"IBindingList.ApplySort called with {property?.Name} {direction}");
ApplySortCore(property, direction);
}
}
class Program
{
static void Main()
{
var result = new List<Journal>
{
new Journal { IDate = DateTime.Now, Name = "A" },
new Journal { IDate = DateTime.Now.AddDays(-1), Name = "B" }
};
var list = new SimpleBindingList<Journal>(result);
var bs = new BindingSource { DataSource = list };
try
{
bs.Sort = "IDate desc"; // Should hit ApplySortCore or fail with error
foreach (Journal item in bs)
{
Console.WriteLine($"{item.IDate} - {item.Name}");
}
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
}
}