3

我有一个自定义对象(MyObject),它实现了 INotifyPropertyChanged 并具有三个属性(一个 int、一个 string 和一个 bool)。这是该对象的代码:

public class MyObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, e);
        }
    }

    private int _Index;
    public int Index
    {
        get { return _Index; }
        set
        {
            if (_Index == value)
            {
                return;
            }

            _Index = value;
            OnPropertyChanged(new PropertyChangedEventArgs("Index"));
        }
    }

    private string _Name;
    public string Name
    {
        get { return _Name; }
        set
        {
            if (_Name == value)
            {
                return;
            }

            _Name = value;
            _Modified = true;
            OnPropertyChanged(new PropertyChangedEventArgs("Name"));
        }
    }

    private bool _Modified;
    public bool Modified
    {
        get { return _Modified; }
        set
        {
            if (_Modified == value)
            {
                return;
            }

            _Modified = value;
            OnPropertyChanged(new PropertyChangedEventArgs("Modified"));
        }
    }

    public MyObject()
    {
    }

    public MyObject(int index, string number, bool modified)
    {
        Index = index;
        Number = number;
        Modified = modified;
    }
}

长话短说,我将这些对象的 BindingList 连接到 DataGridView,如下所示:

BindingList<MyObject> myObjectList = new BindingList<MyObject>();
BindingSource bindingSourceForMyObjects = new BindingSource();

bindingSourceForMyObjects.DataSource = myObjectList;
dataGridViewMyObjects.DataSource = bindingSourceForMyObjects;

当我的应用程序运行时,myObjectList 将填充 100,000 个对象(从文件中读取)并显示在我的 DataGridView 中。我在 DataGridView 中只有一列,它显示我的对象的字符串属性。我的用户可能想要选择 DataGridView 中的所有行并“删除”它们。我在删除术语周围使用引号,因为对象实际上并没有被删除,而是所有 100,000 个对象的字符串属性都设置为 string.Empty。现在,我使用以下代码执行该操作:

myObjectList.ToList().ForEach(c => c.Name = string.Empty);

此操作需要约 55 秒才能完成。我也试过:

foreach (DataGridViewRow row in dataGridViewMyObjects.SelectedRows)
{
    row.Cells["NAME"].Value = string.Empty;
}

这需要 49 秒的时间稍微少一点,但它仍然是一个很长的操作。在旁注中,我还为 bindingSourceForMyObjects 定义了一个 ListChanged 事件处理程序,如下所示:

private void bindingSourceForMyObjects_ListChanged(object sender, ListChangedEventArgs e)
{
    if (e.ListChangedType == ListChangedType.ItemChanged)
    {
        dataGridViewMyObjects.Rows[e.NewIndex].DefaultCellStyle.BackColor = Color.Red;
        dataGridViewMyObjects.Rows[e.NewIndex].DefaultCellStyle.ForeColor = Color.White;
    }
}

如您所见,当我以编程方式更改我的基础对象列表时(就像我将它们全部设置为 string.Empty 时所做的那样),我使用它来直观地指示 DataGridView 中已更改的行。当我“删除”所有对象时,这确实会增加一些开销,但即使没有这个事件处理程序,它仍然是一个冗长的操作。

最后,我的 WinForms 应用程序目前是单线程的,但我计划编写多线程代码,这样做是有意义的。此操作可能是其中一种情况,但在我走这条路之前,还有什么我遗漏的(或做我不需要做的事情)可以提高此操作的性能,所以它不会几乎需要一分钟才能完成?或者这只是处理 100,000 个对象的本质?

4

2 回答 2

3

@User685869 感谢您发布扩展对象。

在完成了一些快速测试示例之后,似乎引发PropertyChanged事件导致速度变慢。删除对它的调用将导致操作在一两秒内完成我的电脑上的 100k 记录。

即使没有事件处理程序,也会发生这种情况。

我假设您已经根据需要实现了接口;如果您不这样做,则将其删除将解决您的问题。

我可以建议的唯一解决方案是创建一个boolean可以设置为 true 的变量,以防止在进行批量更新时引发事件并在之后切换回正常状态。这样做的缺点当然是在进行批量操作时不会引发任何事件。

例如 :-

我的对象

public boolean bulk = false;
public string Name
{
    get { return _Name; }
    set
    {
        if (_Name == value)
        {
            return;
        }

        _Name = value;
        _Modified = true;
        OnPropertyChanged(new PropertyChangedEventArgs("Name"));
    }
}

父代码

_bindingList.ToList().ForEach(c =>
    {
       c.bulk = true;
       c.Name = string.Empty;
       c.bulk = false;
    });
于 2013-01-23T17:44:51.193 回答
1

尝试这个:

dataGridView1.SuspendLayout();
        //do changes
        dataGridView1.ResumeLayout();
于 2013-01-23T16:41:03.977 回答