Keeping a DataGridView autosorted
Asked Answered
P

2

8

I've got a DataGridView that is backed by a SortableBindingList as described by this article.

This is essentially a BindingList whose Data source is a list of custom objects. The underlying custom objects are updated programatically.

My SortableBindingList allows me to sort each column in Ascending or Descending order. I've done this by overloading the ApplySortCore method

protected override void ApplySortCore(PropertyDescriptor prop,
                                      ListSortDirection direction)

This works well for sorting when the column header is clicked on but won't sort automatically when cell in that column is programatically updated.

Has anyone else come up with a good solution for keeping a DataGridView sorted from programmatic updates of its underlying data source?

Perlite answered 24/1, 2013 at 2:30 Comment(0)
G
1

Consider this class:

public class MyClass : INotifyPropertyChanged
{
    private int _id;
    private string _value;

    public int Id
    {
        get
        {
            return _id;
        }
        set
        {
            PropertyChanged(this, new PropertyChangedEventArgs("Id"));
            _id = value;
        }
    }
    public string Value
    {
        get
        {
            return _value;
        }
        set
        {
            PropertyChanged(this, new PropertyChangedEventArgs("Value"));
            _value = value;
        }
    }
    public event PropertyChangedEventHandler PropertyChanged = new PropertyChangedEventHandler(OnPropertyChanged);

    private static void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        // optional code logic
    }
}

Add these methods to your sortable binding list:

public class SortableBindingList<T> : BindingList<T>, INotifyPropertyChanged
    where T : class
{
    public void Add(INotifyPropertyChanged item)
    {
        item.PropertyChanged += item_PropertyChanged;
        base.Add((T)item);
    }

    void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        this.PropertyChanged(sender, new PropertyChangedEventArgs(String.Format("{0}:{1}", sender, e)));
    }

    // other content in the method body
}

And use this sample methods in your form:

public Form1()
{
    InitializeComponent();
    source = new SortableBindingList<MyClass>();
    source.Add(new MyClass() { Id = 1, Value = "one test" });
    source.Add(new MyClass() { Id = 2, Value = "second test" });
    source.Add(new MyClass() { Id = 3, Value = "another test" });
    source.PropertyChanged += source_PropertyChanged;
    dataGridView1.DataSource = source;

}

void source_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    MessageBox.Show(e.PropertyName);
    dataGridView1.DataSource = source;
}

private void button1_Click(object sender, EventArgs e)
{
    ((MyClass)source[0]).Id++;
}
Gerah answered 4/6, 2013 at 13:11 Comment(0)
C
4

Try to override OnDataSourceChanged Event

public class MyGrid : DataGridView {
    protected override void OnDataSourceChanged(EventArgs e)
    {
        base.OnDataSourceChanged(e);
        MyComparer YourComparer = null;
        this.Sort(YourComparer);
    }
}
Couteau answered 29/5, 2013 at 5:51 Comment(1)
thanks for the help. I had tried this but it did not work for notifying me on all programmatic changes to the underlying DataSourcePerlite
G
1

Consider this class:

public class MyClass : INotifyPropertyChanged
{
    private int _id;
    private string _value;

    public int Id
    {
        get
        {
            return _id;
        }
        set
        {
            PropertyChanged(this, new PropertyChangedEventArgs("Id"));
            _id = value;
        }
    }
    public string Value
    {
        get
        {
            return _value;
        }
        set
        {
            PropertyChanged(this, new PropertyChangedEventArgs("Value"));
            _value = value;
        }
    }
    public event PropertyChangedEventHandler PropertyChanged = new PropertyChangedEventHandler(OnPropertyChanged);

    private static void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        // optional code logic
    }
}

Add these methods to your sortable binding list:

public class SortableBindingList<T> : BindingList<T>, INotifyPropertyChanged
    where T : class
{
    public void Add(INotifyPropertyChanged item)
    {
        item.PropertyChanged += item_PropertyChanged;
        base.Add((T)item);
    }

    void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        this.PropertyChanged(sender, new PropertyChangedEventArgs(String.Format("{0}:{1}", sender, e)));
    }

    // other content in the method body
}

And use this sample methods in your form:

public Form1()
{
    InitializeComponent();
    source = new SortableBindingList<MyClass>();
    source.Add(new MyClass() { Id = 1, Value = "one test" });
    source.Add(new MyClass() { Id = 2, Value = "second test" });
    source.Add(new MyClass() { Id = 3, Value = "another test" });
    source.PropertyChanged += source_PropertyChanged;
    dataGridView1.DataSource = source;

}

void source_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    MessageBox.Show(e.PropertyName);
    dataGridView1.DataSource = source;
}

private void button1_Click(object sender, EventArgs e)
{
    ((MyClass)source[0]).Id++;
}
Gerah answered 4/6, 2013 at 13:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.