FormsのListViewは行挿入時、10000行を超えてくるとウィンドウが固まったり、時間がかかったりする。
そこでListViewの行挿入の高速化と+αとして画面が固まらない、挿入途中でキャンセル処理ができるようにする。
ListViewのBeginUpdate()とEndUpdate()による高速化
listView.BeginUpdate();
listView.Items.AddRange(items);
listView.EndUpdate();
BeginUpdate()を呼び出すと、EndUpdate()を呼ぶまでListViewの描画を停止する。
通常時の半分程度の時間で処理が完了するくらいになる。
ただ若干ウィンドウが固る。
ListViewの行挿入時、ウィンドウが固まらないようにする。
public async Task AddRangeAsync(ListView listView, IEnumerable<ListViewItem> items)
{
const int loopCount = 1000;
const int deley = 10;
// long index = 1;
int index = 1;
var item = items.GetEnumerator();
listView.BeginUpdate();
while(item.MoveNext())
{
if ((index++ % loopCount) == 0)
{
//listView.EndUpdate();
// 1000行挿入ごとに少し待つ。
await Task.Delay(deley);
//listView.BeginUpdate();
}
listView.Items.Add(item.Current);
}
listView.EndUpdate();
}
asyncメソッドでListViewの行挿入の処理を行い、1000行くらい挿入するごとに少し中断し、元のUIスレッドが操作できるようにする。
すこし時間はかかるが行挿入時、通常よりウィンドウは固まらない。
Task.Delay()で前後にEndUpdate()、BeginUpdate()を入れて、行が挿入される様子を描画することもできる。
挿入の途中で処理をキャンセルできるようにする。
public async Task AddRangeAsync(ListView listView, IEnumerable<ListViewItem> items, CancellationToken token)
{
const int loopCount = 1000;
const int deley = 10;
int index = 1;
var item = items.GetEnumerator();
listView.BeginUpdate();
while(item.MoveNext() && !token.IsCancellationRequested)
{
if ((index++ % loopCount) == 0)
{
// 1000行挿入ごとに少し待つ。
await Task.Delay(deley);
}
listView.Items.Add(item.Current);
}
listView.EndUpdate();
}
行挿入中にUIスレッドの操作が可能なため、CancellationTokenを使用して、キャンセルイベントなどが発生した際は処理を終了することもできる。
まとめ
・ListView
https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.forms.listview?view=net-5.0