前回「仮想ListViewでIconを表示させるのは諦めたらあかん!」の続き。
いろいろやってみて仮想モードでもIconを表示できたけど、問題山積みで解決できず力尽きた。
右が仮想リストビュー、左が通常のリストビュー。
でも、いくつも問題があって使い物にならない。
- ちらつきが酷い
- 一番下までスクロースさせると、最後の項目のさらに下に隙間ができると、そこにIconが表示されてしまう
- スクロールバーの上下ボタン(▲▼)を押してスクロールすると、ずれたIconが表示されて消えない。
- これらを何とかしようとすると、RetrieveVirtualItemイベントの中でListViewのItemsとかのプロパティ値を見たいのだけれど、そうするとRetrieveVirtualItemイベントが発生してしまい無限ループに・・・
- カラムの高さが取得できない(取り方がわからん)ので、Iconの位置決めするのにマジックナンバー(固定値)を使用。うわー、恥ずかしい!
- ListViewを継承したカスタムコントロールを作って、中で描画の管理をできるようにしようとしたのだが、Itemsプロパティをoverrideしても、仮想モードにすると「設定できない」例外が発生してしまう。ListViewItemCollectionクラスの所為か?
いずれにしてもListViewの継承しての改良では限界がある・・・。
テストプログラムはこちら。
以下はソースの抜粋。listView1_RetrieveVirtualItem()で、ListViewのControlsプロパティにPictureBoxを追加することによりIconが表示される。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
namespace ListViewTEST1
{
public partial class Form1 : Form
{
ListViewItem[] item_;
PictureBox[] pict_;
private const int itemCount = 100;
public Form1()
{
InitializeComponent();
button1.Click += new System.EventHandler(this.button1_Click);
listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
new System.Windows.Forms.ColumnHeader(),
new System.Windows.Forms.ColumnHeader()});
listView1.CheckBoxes = true;
listView1.VirtualMode = true;
listView1.View = View.Details;
listView1.RetrieveVirtualItem += new System.Windows.Forms.RetrieveVirtualItemEventHandler(this.listView1_RetrieveVirtualItem);
listView1.MouseClick += new System.Windows.Forms.MouseEventHandler(this.listView1_MouseClick);
listView1.LargeImageList = new ImageList();
listView1.SmallImageList = new ImageList();
Image image = (Image)ListViewTEST1.Properties.Resources.IMAGE_NOIMAGE;
item_ = new ListViewItem[itemCount];
pict_ = new PictureBox[itemCount];
for (int index = 0; itemCount > index; index++)
{
item_[index] = new ListViewItem(new string[] { index.ToString(), "test" + index.ToString() }, 0);
item_[index].Checked = true;
item_[index].Checked = false;
item_[index].ImageKey = "a" + index.ToString();
listView1.LargeImageList.Images.Add("a" + index.ToString(), image);
listView1.SmallImageList.Images.Add("a" + index.ToString(), image);
pict_[index] = new PictureBox();
pict_[index].Image = listView1.SmallImageList.Images["a" + index.ToString()];
pict_[index].Size = new Size(17, 16);
}
listView1.VirtualListSize = itemCount;
}
private void listView1_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
e.Item = item_[e.ItemIndex];
e.Item.Name = e.ItemIndex.ToString();
Rectangle rect = item_[e.ItemIndex].Bounds;
Trace.WriteLine(
string.Format("RetrieveVirtualItem index={0} listView[VSize,Hight]=[{1},{2}] rect[X,Y,H,W]=[{3},{4},{5},{6}]",
e.ItemIndex, listView1.VirtualListSize, listView1.Height, rect.X, rect.Y, rect.Height, rect.Width));
if ( (rect.Y < 19) ||
((listView1.Height - 19) < rect.Y) )
{
return;
}
pict_[e.ItemIndex].Location = new Point(19, rect.Y);
listView1.Controls.Add(pict_[e.ItemIndex]);
}
private void listView1_MouseClick(object sender, MouseEventArgs e)
{
ListView lv = (ListView)sender;
ListViewItem lvi = lv.GetItemAt(e.X, e.Y);
if (lvi != null)
{
if (e.X < (lvi.Bounds.Left + 16))
{
lvi.Checked = !lvi.Checked;
lv.Invalidate(lvi.Bounds);
}
}
}
}
}
最近のコメント