我有一个包含许多项目的 ListViewItem 默认情况下所有项目都已选中。
我想编写一个函数来获取需要检查的项目列表。
public void NewCheckSecurities(SecurityList oSecurities)
{
// error checking
if (oSecurities == null || oSecurities.Count == 0)
{
return;
}
// check sent securities
ListView.ListViewItemCollection oItems = m_lsvSecurities.Items;
if (oItems != null)
{
int i = 1;
foreach (ListViewItem oItem in oItems)
{
bool bFind = oSecurities.FindSecurity((oItem.Tag as SecurityItem).Security.Symbol) != null;
if(bFind)
{
oItem.Checked = true;
}
else
{
oItem.Checked = false;
}
}
}
}
oSecurities 有 5 种我想检查的证券。
o物品大小 - 2800 件
为了检查问题,我不得不将函数分成两部分(查找、检查)。
第一部分是一个循环,遍历所有项目,只是使 bFind 为 true 或 false。
当我添加第二部分时
if(bFind)
{
oItem.Checked = true;
}
else
{
oItem.Checked = false;
}
它的工作,但太慢了。
当代码执行时 oItem.对 oItems 中的每个 oItem 检查 true 或 false 需要很长时间。
有办法更快地做到这一点吗?
该问题很可能是由组件在每次更新后重新绘制自身引起的。
通常可以通过在进行更改时告诉表单暂停视觉更新来加快速度,如下所示:
this.SuspendLayout();
// Do your updates here
this.ResumeLayout();
它应该运行在
this
等于表单的位置。或者,如果您更喜欢在其他地方运行它,那么您需要将表单作为参数传递给该方法并在那里调用 Suspend...+Resume...。
对于像
ListView
和 DataGridView
这样托管大量项目的控件,提高性能的一种方法是使用 VirtualMode=true
将底层列表项的更改与 UI 绘制分离。由此推论,如果您想要编写一个函数来获取需要检查的项目列表,那么这根本不再需要触摸 UI 并且应该很快。
public partial class MainForm : Form
{
public MainForm() => InitializeComponent();
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
for (int i = 1; i <= 3000; i++)
{
SecuritiesList.Add(new Security { Text = $"Security {i}", IsChecked = false });
}
m_lsvSecurities.View = View.Details;
m_lsvSecurities.HeaderStyle = ColumnHeaderStyle.None;
m_lsvSecurities.Columns.Add("", 80);
m_lsvSecurities.Columns.Add("Security", 300); // Text column with a width of 200 pixels
m_lsvSecurities.CheckBoxes = true;
m_lsvSecurities.VirtualMode = true;
m_lsvSecurities.RetrieveVirtualItem += (sender, e) =>
{
if (e.ItemIndex >= 0 && e.ItemIndex < SecuritiesList.Count)
{
var security = SecuritiesList[e.ItemIndex];
ListViewItem item = new ListViewItem(text: security.IsChecked ? "\u2612" : "\u2610");
item.SubItems.Add(security.Text);
e.Item = item;
}
else
{
e.Item = new ListViewItem();
}
};
m_lsvSecurities.MouseClick += (sender, e) =>
{
var hti = m_lsvSecurities.HitTest(e.Location);
if (hti.Location == ListViewHitTestLocations.Label)
{
var security = SecuritiesList[hti.Item.Index];
security.IsChecked = !security.IsChecked;
m_lsvSecurities.Invalidate(hti.Item.Bounds);
}
};
m_lsvSecurities.VirtualListSize = SecuritiesList.Count;
_ = benchmark();
}
private List<Security> SecuritiesList { get; } = new List<Security>();
}
生成 3000 种证券的列表并显示该列表后,2 秒后调用
benchmark()
方法将它们全部设置为选中。
/// <summary>
/// Show the dialog, then in 2 seconds set the
/// checkboxes to true for 3000 items.
/// </summary>
async Task benchmark()
{
await Task.Delay(TimeSpan.FromSeconds(2));
var stopwatch = Stopwatch.StartNew();
foreach (var item in SecuritiesList)
{
item.IsChecked = true;
}
m_lsvSecurities.Refresh();
stopwatch.Stop();
await Task.Delay(TimeSpan.FromSeconds(0.5));
MessageBox.Show($"{stopwatch.ElapsedMilliseconds} ms");
}
地点:
{
public string Text { get; set; }
public bool IsChecked { get; set; }
}