Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Datagrid column sort is not reacting to databinding changes #10181

Open
Symbai opened this issue Dec 16, 2024 · 6 comments
Open

Datagrid column sort is not reacting to databinding changes #10181

Symbai opened this issue Dec 16, 2024 · 6 comments

Comments

@Symbai
Copy link
Contributor

Symbai commented Dec 16, 2024

Description

Has this been always the case? When I sort a column in a Datagrid by clicking on it, it only sorts the column once. If anything in the cells of the column changes, the column is not sorted again. I tried with and without CollectionView (but I didn't used the collectionview sort because if the Datagrid already has sorting I expect it to work on its own)

Shouldn't the column sort react to databinding changes? What's the purpose of allowing sort in WPF when, if it has to react on databinding changes, we have to add our own sorting instead?

Reproduction Steps

  1. Use code below
  2. Launch app
  3. Click on the column to sort
  4. Press the button
<Window
    x:Class="WpfApp12.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:WpfApp12"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="800"
    Height="450"
    mc:Ignorable="d">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Button
            Grid.Row="0"
            Click="Button_Click"
            Content="Make Changes" />
        <DataGrid
            Grid.Row="1"
            AutoGenerateColumns="False"
            ItemsSource="{Binding Items}">
            <DataGrid.Columns>
                <DataGridTextColumn
                    Width="200"
                    Binding="{Binding Name}"
                    CanUserSort="True"
                    Header="Name" />
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        DataContext = this;
        InitializeComponent();
        Items.Add(new MyData { Name = "Item 1" });
        Items.Add(new MyData { Name = "Item 2" });
        Items.Add(new MyData { Name = "Item 3" });
        Items.Add(new MyData { Name = "Item 4" });
        Items.Add(new MyData { Name = "Item 5" });
    }

    public ObservableCollection<MyData> Items { get; } = new();

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Items[2].Name = "Changed";
    }
}
public class MyData : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    string _Name;
    public string Name
    {
        get => _Name;
        set
        {
            if (value == _Name) return;
            _Name = value;
            OnPropertyChanged(nameof(Name));
        }
    }
}

Expected behavior

Image

Actual behavior

Image

Regression?

No response

Known Workarounds

No response

Impact

No response

Configuration

.NET 8.0
x64

Other information

No response

@miloush
Copy link
Contributor

miloush commented Dec 16, 2024

Live shaping, which I believe is the feature you are looking for, was introduced in .NET Framework 4.5 and is not enabled by default for performance reasons.

You need to enable it on the collection view / source, see IsLiveSorting.

@Symbai
Copy link
Contributor Author

Symbai commented Dec 16, 2024

That works but why isn't there such a property on Datagrid itself? Datagrid allows binding to ObservableCollection. But only for a thing such as live sorting you have to bind Datagrid to an CollectionView which is created by an CollectionViewSource which is bound to your ObservableCollection? Seems unnecessarily overcomplicated to me.

@MichaeIDietrich
Copy link
Contributor

Features like sorting, grouping and filtering can be used on any control that displays lists of data (e.g. DataGrid, ListBox).
Implementing this on data level rather than control level gives the best flexibility in my opinion.

Let's imagine you have a single ObservableCollection with lots of data.

Now you can simply create a CollectionViewSource like the following in XAML and share it with as many controls as you wish, but only have to calculate filtering, sorting and grouping once, which wouldn't be the case when it was only available on control level. Depending on the amount of data, this can save a fair amount of computation power.

<CollectionViewSource x:Key="BookViewSource" Source="{Binding BookList}" IsLiveFilteringRequested="True">
    <CollectionViewSource.LiveFilteringProperties>
        <clr:String>IsReleased</clr:String>
    </CollectionViewSource.LiveFilteringProperties>
    <CollectionViewSource.SortDescriptions>
        <scm:SortDescription PropertyName="Title" />
    </CollectionViewSource.SortDescriptions>
</CollectionViewSource>

I would say this concept is a good compromise to give the flexibility to create as many collection views for the same list of data and reuse it as much as you need and want.

Personally I tend to create ListCollectionViews for an ObservableCollection in the view model layer and set up things there and then simply bind to the ListCollectionView directly instead.

I hope this makes sense. 😄

@himgoyalmicro
Copy link
Contributor

@Symbai are we good to close this issue?

@himgoyalmicro himgoyalmicro added the 📭 waiting-author-feedback To request more information from author. label Dec 18, 2024
@Symbai
Copy link
Contributor Author

Symbai commented Dec 18, 2024

Implementing this on data level rather than control level gives the best flexibility in my opinion.

Makes sense EXCEPT the fact that Datagrid provides sorting on control level, by end user. This is different comparing to a Listbox. And I believe it should use live sorting by default. Because that is what the end user would expect. If you sort by filename in Windows explorer and then change a filename, it's properly sorted and not stuck like in WPF. And on other UI frameworks its the same. If there are performance concerns a developer would simply disallow sorting and sort by himself using CollectionViewSource.

@himgoyalmicro Well while my original question has been answered, I'm currently trying to discuss whether we should change the behavior.

@dotnet-policy-service dotnet-policy-service bot removed the 📭 waiting-author-feedback To request more information from author. label Dec 18, 2024
@omariom
Copy link
Contributor

omariom commented Dec 28, 2024

Because that is what the end user would expect.

Most people don’t expect rows to shuffle around just because they sorted the datagrid.
They usually sort so they can find what they need, copy data, or export it to CSV or Excel.
Live sorting is powerful but not used very often, and it can slow down large datasets.
It’s best to keep it off by default.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants