This is a migrated thread and some comments may be shown as answers.

BindingList and INotifyPropertyChanged performance

16 Answers 1176 Views
GridView
This is a migrated thread and some comments may be shown as answers.
codicezerouno
Top achievements
Rank 1
codicezerouno asked on 02 Mar 2011, 09:53 AM
Hi guys,

I fall into a problem of performance when binding a BindingList<T> to a grid where T implements INotifyPropertyChanged interface.

Exactly, what happens is that, having a lot of rows (10000), when I change a property of one object the FirePropertyChanged method takes some seconds and I don't understand why.

Can someone help me about that?

Thanks in advance.

Stefano.

16 Answers, 1 is accepted

Sort by
0
Emanuel Varga
Top achievements
Rank 1
answered on 02 Mar 2011, 10:03 AM
Hello Stefano,

And you are not doing anything else in the OnPropertyChanged of the objects?
If not, can you please provide some more info, like the number of columns and so on, so that i can prepare a test app with this.

Hope this helps, if you have any other questions or comments, please let me know,

Best Regards,
Emanuel Varga
Telerik WinForms MVP
0
codicezerouno
Top achievements
Rank 1
answered on 02 Mar 2011, 11:25 AM
Hi Emanuel,

thank you for your fast response!

I never handle the PropertyChanged event in my code, and I use it only to notify the grid on data changed.

This is the interface implementation:
#region INotifyPropertyChanged Members
 
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
 
protected bool CheckPropertyChanged<T>(string propertyName, T oldValue, T newValue)
{
    if (oldValue == null && newValue == null)
    {
        return false;
    }
 
    if ((oldValue == null && newValue != null) || (oldValue != null && newValue == null) || !oldValue.Equals((T)newValue))
    {
        FirePropertyChanged(propertyName);
        return true;
    }
 
    return false;
}
 
public void FirePropertyChanged(string propertyName)
{
    if (this.PropertyChanged != null)
    {
       this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
    }
}
 
#endregion

and I use it on this property of my object:
public bool IsChecked { get { return isChecked; } set { var oldvalue = isChecked; isChecked = value; CheckPropertyChanged<bool>("IsChecked", oldvalue, value); } }

What I do is to fill a BindingList<MyObj> and with it I set grid.DataSource; at this point the grid (40k rows and 20 columns) takes 30 seconds to bind.
Then, when I change, programmatically, IsChecked property of one of the objects in the list calling "this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName))"takes 45 seconds.

Let me know and do not esitate to ask me any other info.

Thanks a lot,
Stefano.
0
Emanuel Varga
Top achievements
Rank 1
answered on 02 Mar 2011, 11:39 AM
Hello again Stefano,

Can you please try this more conventional approach to INotifyPropertyChanged, like the following class for example:
Please try it if possible like this and let me know what if it's the same or not:
public class CustomClass : INotifyPropertyChanged
{
    private bool check;
 
    public bool Check
    {
        get { return check; }
        set
        {
            if (check != value)
            {
                check = value;
                OnPropertyChanged("Check");
            }
        }
    }
 
    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
 
    #region INotifyPropertyChanged Members
 
    public event PropertyChangedEventHandler PropertyChanged;
 
    #endregion INotifyPropertyChanged Members
}

Hope this helps, if you have any other questions or comments, please let me know,

Best Regards,
Emanuel Varga
Telerik WinForms MVP
0
codicezerouno
Top achievements
Rank 1
answered on 02 Mar 2011, 11:53 AM
Hello Emanuel,

I tried the solution you propose but nothing changes: executing "PropertyChanged(this, ...)" takes a lot of seconds.

Best Regards,
Stefano.
0
Emanuel Varga
Top achievements
Rank 1
answered on 02 Mar 2011, 12:06 PM
Hello again Stefano,

Sorry, i just cannot reproduce this, please try the following and let me know of the results:
using System;
using System.ComponentModel;
using System.Windows.Forms;
using Telerik.WinControls.UI;
 
public partial class Form1 : Form
{
    private RadGridView radGridView1;
    public Form1()
    {
        InitializeComponent();
        this.Size = new System.Drawing.Size(800, 600);
 
        this.Controls.Add(radGridView1 = new RadGridView());
        radGridView1.Dock = DockStyle.Fill;
        radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
 
        var list = new BindingList<Person>();
        for (int i = 0; i < 100000; i++)
        {
            list.Add(new Person(i, "Person"+i, i%2 == 0, i% 20 == 0, DateTime.Now.AddHours(i), DateTime.Now.AddHours(-i)));
        }
 
        radGridView1.DataSource = list;
    }
 
    private class Person : INotifyPropertyChanged
    {
        private int id;
 
        public int Id
        {
            get { return id; }
            set
            {
                id = value;
                OnPropertyChanged("Id");
            }
        }
        private string name;
 
        public string Name
        {
            get { return name; }
            set
            {
                name = value;
                OnPropertyChanged("Name");
            }
        }
        private bool alive;
 
        public bool Alive
        {
            get { return alive; }
            set
            {
                alive = value;
                OnPropertyChanged("Alive");
            }
        }
        private bool inDept;
 
        public bool InDept
        {
            get { return inDept; }
            set
            {
                inDept = value;
                OnPropertyChanged("InDept");
            }
        }
        private DateTime dateOfBirth;
 
        public DateTime DateOfBirth
        {
            get { return dateOfBirth; }
            set
            {
                dateOfBirth = value;
                OnPropertyChanged("DateOfBirth");
            }
        }
        private DateTime updateDate;
 
        public DateTime UpdateDate
        {
            get { return updateDate; }
            set
            {
                updateDate = value;
                OnPropertyChanged("UpdateDate");
            }
        }
 
        public Person(int id, string name, bool alive, bool inDept, DateTime birthDate, DateTime update)
        {
            this.Id = id; this.Name = name; this.Alive = alive; this.InDept = inDept; this.DateOfBirth = birthDate; this.UpdateDate = update;
        }
 
        #region INotifyPropertyChanged Members
 
        public event PropertyChangedEventHandler PropertyChanged;
 
        #endregion
 
        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

Hope this helps, if you have any other questions or comments, please let me know,

Best Regards,
Emanuel Varga
Telerik WinForms MVP
0
Accepted
Richard Slade
Top achievements
Rank 2
answered on 02 Mar 2011, 12:45 PM
Hi Guys,

@Stefano, yes, I can replicate your issue. With Emanuel's sample which follows the standard pattern for INotifyPropertyChanged when running all appears to be fine. However, sorting takes around 20 seconds and then editing any column takes around 30 seconds (after sorting).

I will see if I can come up with any suggestions for you, in the meantime if you have any questions, please let me know
Thanks
Richard
0
Richard Slade
Top achievements
Rank 2
answered on 02 Mar 2011, 01:04 PM
Hello,

Ok, I know we are dealing with 100,000 rows here, which is quite a few, but editing takes a long time after sorting which doesn't happen before sorting. This may be related to this issue in the Public Issue Tracking System which is resolved in the up coming release. Note the comments in the issue, that editing was slow after sorting.

I have also verified that removing the INotifyPropertyChanged interface, this still occurs.
Regards,
Richard
0
codicezerouno
Top achievements
Rank 1
answered on 02 Mar 2011, 02:54 PM
Hi guys,

I confirm the Richard answer: my grid has sorting and filtering enabled and if I disable them, the grid become faster.

Refer to Emanuel test sample, if I need to make a massive change, for example invert the value of Alive field for all items, which the best approch?

if I do this, it takes a lot:
private void button1_Click(object sender, EventArgs e)
{
     for (int i = 0; i < list.Count; i++)
        list[i].Alive = !list[i].Alive;
}

but, If I do this, it takes few time (on ResetBindings); is that correct?
private void button1_Click(object sender, EventArgs e)
{
    list.RaiseListChangedEvents = false;
    for (int i = 0; i < list.Count; i++)
        list[i].Alive = !list[i].Alive;
    list.RaiseListChangedEvents = true;
    list.ResetBindings();
}
0
Richard Slade
Top achievements
Rank 2
answered on 02 Mar 2011, 03:10 PM
Hello,

Yes, your second method would be quick as you are not raising the changed events as you loop over the list, and then are notifying the grid of the changes after by calling ResetBindings. You can read a full exmaple of ResetBindings at this MSDN Link

I hope this helps but let me know if you have further questions
Richard
0
Emanuel Varga
Top achievements
Rank 1
answered on 02 Mar 2011, 03:10 PM
Hello Stefano,

For this you can wrap your change in either a
using (radGridView.DeferRefresh())
{
// perform required changes
}
 
// or
radGridView.BeginUpdate();
//perform required changes
radGridView.EndUpdate();

Hope this helps, if you have any other questions or comments, please let me know,

Best Regards,
Emanuel Varga
0
Accepted
Richard Slade
Top achievements
Rank 2
answered on 02 Mar 2011, 03:18 PM
Hi Emanuel,

Sadly, the DeferRefresh has no effect on this sample. What makes the performance difference is
list.RaiseListChangedEvents = false;
// loop
list.RaiseListChangedEvents = true;
list.ResetBindings();
though I also would have thought that using DeferRefresh should have made a difference.
Let me know if you have any questions or comments
Richard
0
codicezerouno
Top achievements
Rank 1
answered on 03 Mar 2011, 12:29 PM
So, we are assuming that there is a problem of performance, maybe not directly related to INotifyPropertyChanged interface.

@Richard: do you really think it could be related to that "issue" (you linked), or could be right to open a new issue?
0
Richard Slade
Top achievements
Rank 2
answered on 03 Mar 2011, 12:35 PM
Hello,

I think it is likey that it is related, and it is highly probable that Telerik have already seen this thread, however, for qiucker support it may be worth opening a support ticket and quoting this forum thread so that Telerik are able to keep a trail of the issue. When opening a support ticket, it will be useful to include a very basic project to replicate the issue.

If I can be of further help though, or you need me to open the ticket, please just let me know
Thanks
Richard
0
codicezerouno
Top achievements
Rank 1
answered on 03 Mar 2011, 12:37 PM
In the meanwhile, cause I cannot remove sorting and filtering functionality to the customer, I found a work around:

I stop using INotify... interface and, after change a property value, I call grid.CurrentView.UpdateView() or .InvalidateRow() if you know the row.

Stefano.
0
Michael
Top achievements
Rank 1
answered on 19 Jun 2017, 09:57 PM
As codicezerouno suggested I switched to grid.CurrentView.UpdateView()  also from INotify interface because it was too slow when changing many bound elements.  I guess in 6 years this hasn't been able to be fixed.
0
Dess | Tech Support Engineer, Principal
Telerik team
answered on 21 Jun 2017, 08:17 AM
Hello Michael, 

Thank you for writing.  

I have tested with 100000 records and tried to update a cell value after the column is sorted. The records are a considerable count and it is normal to affect performance when editing a cell value in a sorted grid. This will trigger the sorting operation again because the row should be positioned according to the new cell value. I would recommend you to use RadVirtualGrid which is a grid component developed on top of Telerik Presentation Framework which provides a convenient way to implement your own data management operations and optimizes the performance when interacting with large amounts of data. Additional information is available in the online documentation: http://docs.telerik.com/devtools/winforms/virtualgrid/overview

I hope this information helps. Should you have further questions I would be glad to help.

Regards,
Dess
Progress Telerik
Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
Tags
GridView
Asked by
codicezerouno
Top achievements
Rank 1
Answers by
Emanuel Varga
Top achievements
Rank 1
codicezerouno
Top achievements
Rank 1
Richard Slade
Top achievements
Rank 2
Michael
Top achievements
Rank 1
Dess | Tech Support Engineer, Principal
Telerik team
Share this question
or