0

I have the next problem. There is some WPF dialog with DataGrid. This DataGrid displays some table. Table contains 1 column with a Date. This Date property is represented as a string. In most cases, Date has some value that we read from the database. But in some cases user can create a new record in this table. In this case, the Date should be null (with a "null" value, not a String.Empty). And it should be written to the database as null. Also the cell in the table for "null" Date should be empty. So it's why we use for it a string type.

The DataGrid ItemSource property has binding to the ICollectionView MyView property from the view model. Also, the view model contains other property related to my collection of data and is used for the MyView:

public class MyCustomObject
{
    public string Date { get; set; }
   
    // some other properties.
}

public class MyViewModel
{
    public ObservableCollection<MyCustomObject> TableItems
    {
       get { return tableItems; }
       set
       {
          Set(ref tableItems, value, true);
          TableView = CollectionViewSource.GetDefaultView(tableItems);
       }
    }

    public virtual ICollectionView TableView
    {
       get { return tableView; }
       set
       {
          Set(ref tableView, value);
       }
    }

    public MyViewModel()
    {
        var someCollection = new List<MyCustomObject>();
        TableItems = new ObservableCollection<MyCustomObject>(someCollection);
    }
}

In some method of MyViewModel I've added the sorting for my collection by ICollectionView.SortDescriptions. Like:

TableView.SortDescriptions.Add(new SortDescription(nameof(MyCustomObject.Date), ListSortDirection.Ascending));

All works. But as my Date is a string it's compared as a string. So I can get something like this:

02/10/19
03/09/19
03/10/20
04/08/17

How can I add some custom comparer to my TableView and change the sorting logic for some property? Should I have to add the custom comparer to the my someCollection in the constructor before adding it to the TableItems?

5ORBEX
  • 81
  • 7
  • 2
    This might help: https://stackoverflow.com/questions/24147585/collectionviewsource-with-custom-sort – Joe Jan 12 '23 at 17:23
  • Thanks, I'll check it. But I don't understand how can I get the ICollectionViewSource from the ICollectionView to set the CustomSort property? – 5ORBEX Jan 12 '23 at 17:29

1 Answers1

1

You must cast the ICollectionView to ListCollectionView.

Depending on the actual collection, the view returned by CollectionViewSource.GetDefaultView is an implementation of ICollectionView.
For collections of type IList this is the ListCollectionView.

Also consider to use a DateTime instead of string to store the date.

The following example creates a date string IComparer or an alternate DateTime IComparer and assigns it to the collection's view:

var listCollectionView = (ListCollectionView)CollectionViewSource.GetDefaultView(this.TableItems);

// To compare DateTime 
Comparer<DateTime> dateTimeComparer = Comparer<DateTime>.Create(DateTime.Compare);

// To compare date strings.
// Optionally define the date culture for DateTime.Parse
CultureInfo dateCulture = CultureInfo.CurrentCulture;

Comparison<string> dateTimeStringComparison = (stringX, stringY) 
  => DateTime.Compare(DateTime.Parse(stringX, dateCulture), DateTime.Parse(stringY, dateCulture));
Comparer<string> dateTimeStringComparer = Comparer<string>.Create(dateTimeStringComparison);

listCollectionView.CustomSort = dateTimeStringComparer;
BionicCode
  • 1
  • 4
  • 28
  • 44
  • Thanks for the answer and explanation. But I also have 1 more question. When we create the custom comparer to set it to the CustomSort property, it means that this comparer should compare the whole object in this collection, right? So does it mean that it always will sort table records by all properties in the object? Because in my case I should sort records by one property whose name I set to the SortDescription. – 5ORBEX Jan 12 '23 at 18:51
  • You define a SortDescription that defines the property of the collection item to use as input for the predicate. Then the custom IComparer is applied to every item of the collection: the value of the property defined by the SortDescriptor is passed to the IComparer for comparison. – BionicCode Jan 12 '23 at 18:55
  • *"So does it mean that it always will sort table records by all properties in the object?"* - No. It will use the property defined by the SortDescriptor. If there is no SortDesciptor defined, the collection won't get sorted. – BionicCode Jan 12 '23 at 18:58
  • But how this custom comparer knows what property should it use for the main sorting? For example, let's imagine that my MyCustomObject has 3 properties: string Date, string Name, int Number. In case when I add SortDescription with "Date" I want to use your custom comparer to sort records in the table. And the order should be as in my first answer. But If I remove the first SortDescription and add other one with "Name" it should use sort only by Name property, and order should be other. The same thing for the Number. – 5ORBEX Jan 12 '23 at 19:09
  • 1
    You needed the custom comparer to enable proper date sorting: because your Date property is of type `string` the collection view would use lexical sorting (`string.Compare`). Now, if you remove the SortDescription for the Date property, you would also have to remove the custom comparer (`collectionView.CustomSort = null`). If you had defined the Date property of type `DateTime`, you would eliminate the need for a custom comparer as the collection view would now sort Date correctly (because there is a default comparer for DateTime i.e DateTime implements IComparable). – BionicCode Jan 12 '23 at 19:32