カテゴリー別

お絵描き、デザイン

写真、動画関連ソフト

アメーバピグ専用ソフト

ホームページ関連

画像処理

スキャナー用

SEO 関連

お楽しみ

その他

過去ログ

2011年05月27日(金)

c# 仮想 ListView で選択項目削除の高速化

仮想 ListView については前回のブログを見てください。
(過去ログ:c# 仮想 ListView で全て選択するには)

仮想 ListView で、選択項目を削除しようとして以下のようなコードを書くと
異常に遅いです。

int count = listView1.SelectedIndices.Count;
for (int i = count - 1; i >= 0; -- i)
  items.RemoveAt(listView1.SelectedIndices[i]);

なんと、環境にもよりますが、1万件の削除に 43 秒もかかりました !
しかも原因は RemoveAt ではなくて、SelectedIndices[i] です。

なんでやねーんw。

なので、下のように修正すると異常にはやくなります。

int count = listView1.SelectedIndices.Count;
int[] indices = new int[count];
listView1.SelectedIndices.CopyTo(indices, 0);
for (int i = count - 1; i >= 0; -- i)
  items.RemoveAt(indices[i]);

なんと、自分の環境では、10 ミリ秒。

ぴゃーわけわからん。(by よゐこ、はまぐちぇ)

一応、↓がスクリーンショットとデザイナで生成してない部分の全コードです。

リストビューテスト用フォーム

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Forms;

namespace ListViewTest
{
  partial class Form1 : Form
  {
    List items = new List();

    public Form1()
    {
      InitializeComponent();
      
      listView1.HideSelection = false;
      listView1.VirtualMode = true;
      listView1.View = System.Windows.Forms.View.Details;

      listView1.Columns.Add(new ColumnHeader());
      listView1.Columns[0].Text = "no";

      listView1.RetrieveVirtualItem += listView1_RetrieveVirtualItem;
      buttonInit.Click += buttonInit_Click;
      buttonSelectAll.Click += buttonSelectAll_Click;
      buttonDelete.Click += buttonDelete_Click;
    }

    private void listView1_RetrieveVirtualItem(
      object sender, RetrieveVirtualItemEventArgs e
    )
    {
      e.Item = items[e.ItemIndex].CreateListViewItem();
    }

    private void buttonInit_Click(object sender, EventArgs e)
    {
      listView1.BeginUpdate();

      items.Clear();
      for (int i = 0; i < 10000; ++ i)
        items.Add(new VirtualItem(i));
      listView1.VirtualListSize = items.Count;

      listView1.EndUpdate();
    }

    private void buttonSelectAll_Click(object sender, EventArgs e)
    {
      Stopwatch watch = Stopwatch.StartNew();

      listView1.BeginUpdate();

      listView1.SelectedIndices.Clear();
      for (int i = 0; i < items.Count; ++ i)
        listView1.SelectedIndices.Add(i);

      listView1.EndUpdate();

      MessageBox.Show(watch.ElapsedMilliseconds.ToString()); // 236 ミリ秒
    }

    private void buttonDelete_Click(object sender, EventArgs e)
    {
      Stopwatch watch = Stopwatch.StartNew();

      listView1.BeginUpdate();

#if true
      // 43 秒もかかる !! //
      int count = listView1.SelectedIndices.Count;
      for (int i = count - 1; i >= 0; -- i)
        items.RemoveAt(listView1.SelectedIndices[i]);
#else
      // 10 ミリ秒 !! //
      int count = listView1.SelectedIndices.Count;
      int[] indices = new int[count];
      listView1.SelectedIndices.CopyTo(indices, 0);
      for (int i = count - 1; i >= 0; -- i)
        items.RemoveAt(indices[i]);
#endif

      listView1.VirtualListSize = items.Count;
      listView1.EndUpdate();
      MessageBox.Show(watch.ElapsedMilliseconds.ToString());
    }
  }

  class VirtualItem
  {
    public int no;
    
    public VirtualItem(int no)
    {
      this.no = no;
    }

    public ListViewItem CreateListViewItem()
    {
      ListViewItem item = new ListViewItem(no.ToString());
      return item;
    }
  }
}

XNA を用いた最新の画像ビューア: ミルノ PC フォトフレーム
ローカルの HTML をカンタンに見られる: ローカルブラウザ
複雑な縁取り文字をカンタンに作成できる: 文字に縁取りするノ


コメント
コメントする