我正在编写一个包含这样一个简单对象的 WinForms 应用程序:
public class MyObject : INotifyPropertyChanged // for two-way data binding
{
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName] string caller = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(caller));
}
}
private int _IndexValue;
public int IndexValue
{
get { return Value; }
set
{
if (value != Value)
{
Value = value;
RaisePropertyChanged();
}
}
}
private string _StringValue;
public string StringValue
{
get { return _StringValue; }
set
{
if (value != _StringValue)
{
_StringValue = value;
_Modified = true;
RaisePropertyChanged();
}
}
}
private bool _Modified;
public bool Modified
{
get { return _Modified; }
set
{
if (value != _Modified)
{
_Modified = value;
RaisePropertyChanged();
}
}
}
public MyObject(int indexValue)
{
IndexValue = indexValue;
StringValue = string.Empty;
Modified = false;
}
}
我有一个 BindingList,它将包含我的对象的固定数量 (100,000) 以及一个 BindingSource。这两个都是这样定义的:
BindingList<MyObject> myListOfObjects = new BindingList<MyObject>();
BindingSource bindingSourceForObjects = new BindingSource();
bindingSourceForObjects .DataSource = myListOfObjects;
最后,我有了我的 DataGridView 控件。它有单列(“STRINGVALUECOLUMN”),它显示我的对象的 StringValue 属性,它绑定到我刚刚提到的 BindingSource:
dataGridViewMyObjects.DataSource = bindingSourceForObjects;
当我的应用程序启动时,我将 100,000 个对象添加到 myListOfObjects。由于我的 DGV 中只有一列,并且它显示的属性初始化为 string.Empty,因此我基本上有一个包含 100,000 个“空白”行的 DGV。此时,我的用户可以开始编辑行以输入字符串。他们不必按任何顺序编辑它们,因此他们可能会在第一行中放置一个字符串,在第 17 行中放置下一个字符串,在第 24581 行中放置下一个字符串等。有时,我的用户会想要从文本文件中导入字符串. 由于我有固定数量的对象 (100,000),并且可能已经输入了一些现有字符串,也可能没有输入,因此在添加新字符串之前,我需要在导入过程中执行一些检查。在下面的代码中,我删除了这些检查,但它们似乎不会影响我的应用程序的性能。但是,如果我使用下面的代码导入数万个字符串,它会非常慢(比如导入 50k 行需要 4 或 5 分钟)。我已将其范围缩小到此代码块中的某些内容:
// this code is inside the loop that reads each line from a file...
// does this string already exist?
int count = myListOfObjects.Count(i => i.StringValue == stringFromFile);
if (count > 0)
{
Debug.WriteLine("String already exists!"); // don't insert strings that already exist
}
else
{
// find the first object in myListOfObjects that has a .StringValue property == string.Empty and then update it with the string read from the file
MyObject myObject = myListOfObjects.FirstOrDefault(i => i.StringValue == string.Empty);
myObject.StringValue = stringFromFile;
}
我的理解是我需要双向绑定,因此我可以更新基础数据并将其反映在 DGV 控件中,但我也读到 INotifyPropertyChanged 有时可能会很慢。有没有人遇到过这个问题?如果是这样,您是如何解决的?
--更新--
仅出于测试目的,我替换了:
// does this string already exist?
int count = myListOfObjects.Count(i => i.StringValue == stringFromFile);
if (count > 0)
{
Debug.WriteLine("String already exists!"); // don't insert strings that already exist
}
else
{
// find the first object in myListOfObjects that has a .StringValue property == string.Empty and then update it with the string read from the file
MyObject myObject = myListOfObjects.FirstOrDefault(i => i.StringValue == string.Empty);
myObject.StringValue = stringFromFile;
}
带有一个 for 循环,其中包含:
myListOfObjects[counter].StringValue = "some random string";
即使有 100,000 个对象,这也非常快。但是,我现在失去了以下能力:1)在分配之前检查我从文件中读取的字符串是否已经分配给列表中的对象,以及 2)在列表中找到其 StringValue 的第一个可用对象property == string.Empty 然后相应地更新该值。所以看起来:
int count = myListOfObjects.Count(i => i.StringValue == stringFromFile);
和
MyObject myObject = myListOfObjects.FirstOrDefault(i => i.StringValue == string.Empty);
...是我的性能问题的根源。是否有更快、更有效的方法来针对我的 BindingList 执行这两个操作?