Ayub
Ayub

Reputation: 2375

Custom sorting Datagrid

I have a Datagrid which has only one column and I want applying a custom sort on it. Currently, When I search the word "Clark", Datagrid displays filtered result as this:

David Clark
Clark David

But I want to display that item which start with FilterString at first row:

Clark David
David Clark

If user search "David", the result should be:

David Clark
Clark David

This is my datagrid:

<TextBox Name="SearchBox" KeyUp="SearchBox_OnKeyUp" />
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding WordsCollectionView}">
    <DataGrid.Columns>
         <DataGridTextColumn Width="*" Binding="{Binding}" />
    </DataGrid.Columns>
</DataGrid>

And this is my codebehind:

string[] words = { "David Clark", "Clark David", "John Smith"};
private string _filterString = "";

private ICollectionView _wordsCollectionView;
public ICollectionView WordsCollectionView
{
    get => _wordsCollectionView;
    set { _wordsCollectionView = value; OnPropertyChanged(); }
}

public MainWindow()
{
    InitializeComponent();

    WordsCollectionView = CollectionViewSource.GetDefaultView(words);
        WordsCollectionView.Filter = FilterResult;
        DataContext = this;
}

public string FilterString
{
    get => _filterString;
    set
    {
       _filterString = value;
       OnPropertyChanged();
       FilterCollection();
    }
}

public bool FilterResult(object obj)
{
    string str = obj as string;
    return str.Contains(FilterString);
}

private void FilterCollection()
{
    _wordsCollectionView?.Refresh();
}

private void SearchBox_OnKeyUp(object sender, KeyEventArgs e)
{
    FilterString = (sender as TextBox).Text;
}        

Upvotes: 0

Views: 249

Answers (2)

mm8
mm8

Reputation: 169200

If you cast WordsCollectionView to a ListCollectionView, you could set its CustomSort property to an IComparer where you implement your custom sorting logic. Something like this:

public MainWindow()
{
    InitializeComponent();

    WordsCollectionView = CollectionViewSource.GetDefaultView(words);
    WordsCollectionView.Filter = FilterResult;
    var listCollectionView = WordsCollectionView as ListCollectionView;
    if (listCollectionView != null)
        listCollectionView.CustomSort = new CustomSorter(this);
    DataContext = this;
}

private class CustomSorter : IComparer
{
    private readonly MainWindow _window;

    public CustomSorter(MainWindow window)
    {
        _window = window;
    }

    public int Compare(object x, object y)
    {
        int a = x?.ToString().IndexOf(_window.FilterString) ?? -1;
        int b = y?.ToString().IndexOf(_window.FilterString) ?? -1;
        return a.CompareTo(b);
    }
}

Upvotes: 1

Corentin Pane
Corentin Pane

Reputation: 4943

You can set both filtering and sorting on an ICollectionView:

WordsCollectionView.Filter = FilterResult
WordsCollectionView.SortDescriptions.Add(new SortDescription("", ListSortDirection.Ascending)); //words have no property

See this MSDN page for full details.

Note that this will result in the sorting you want, but for more advanced sorting you should consider having two columns instead of one, one for the first name and one for the last name.

Upvotes: 1

Related Questions