【发布时间】:2021-07-21 20:00:41
【问题描述】:
我正在尝试使用大量数据更新 ListBox 并同时保持 UI 响应。
这是我用来实现此目的的代码,遍历 10000 个项目,将它们收集到 100 个项目的批次中,然后一次性插入这 100 个项目,这样我就可以避免每次添加单个项目时更新 UI,但不幸的是,代码不起作用,只有在将所有 10000 个项目实际添加到 ListBox 后,才会更新 UI。
public partial class Form1 : Form
{
private SynchronizationContext synchronizationContext;
public Form1()
{
InitializeComponent();
}
private async void button1_Click(object sender, EventArgs e)
{
synchronizationContext = SynchronizationContext.Current;
await Task.Run(() =>
{
ConcurrentDictionary<int, int> batch = new ConcurrentDictionary<int, int>();
int count = 0;
for (var i = 0; i <= 10000; i++)
{
batch[i] = i;
count++;
if (count == 100)
{
count = 0;
UpdateUI(batch);
batch = new ConcurrentDictionary<int, int>();
}
}
});
}
private void UpdateUI(ConcurrentDictionary<int, int> items)
{
synchronizationContext.Post(o =>
{
listBox1.SuspendLayout();
foreach (var item in items)
{
listBox1.Items.Add(item.Value);
}
listBox1.ResumeLayout();
}, null);
}
}
【问题讨论】:
-
您可以用
BeginInvoke()替换整个 SynchronizationContext 和 Post() 方法调用(因为所有方法都在同一个 Form 类中工作。否则,传递一个 Progress<T> 委托:这是一个简化的方法将 Post() 发送到 SynchronizationContext 而不显式捕获它,IProgress<T>委托会为您执行此操作)。那么,你不需要SuspendLayout()/ResumeLayout()(无关),而是BeginUpdate()/EndUpdate()。 -
a) AddRange b) 如果你关心 UI,为什么要添加这么多项目??
标签: c# winforms async-await listbox