0

I have a System.Windows.Forms.ListView. Under normal (non-virtual) operation, the ListViewItems have their images correctly shown. However, when I try to convert the ListView to virtual mode, the items no longer have their images displayed. Everything else (text, index, etc.) is displayed as intended.

The ListView is in Details mode. SmallImageList is correctly set. Each ListViewItem has its ImageKey correctly set. The ImageList has been correctly populated.

Why is the image not being displayed on a virtual ListView? What can I do to ensure that the image is displayed as intended?

Edit: Please see the following code as an example that demonstrates the problem I am having.

static class Program
{
    [STAThread]
    static void Main(string[] args)
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new VirtualListViewExample());
    }
}

class VirtualListViewExample : Form
{
    public VirtualListViewExample()
    {
        Image image = new Bitmap(16, 16);
        using (Graphics g = Graphics.FromImage(image))
        {
            g.FillRectangle(Brushes.Black, 0, 0, 16, 16);
        }

        ImageList imageList = new ImageList();
        imageList.ColorDepth = ColorDepth.Depth32Bit;
        imageList.ImageSize = new Size(16, 16);
        imageList.Images.Add("key", image);

        ListView normalList = new ListView();
        normalList.Columns.Add("Column");
        normalList.Dock = DockStyle.Fill;
        normalList.View = View.Details;
        normalList.VirtualMode = false;
        normalList.SmallImageList = imageList;
        for (int i = 0; i < 100; i++)
        {
            ListViewItem item = new ListViewItem();
            item.Text = "Item " + i.ToString();
            item.ImageKey = "key";
            normalList.Items.Add(item);
        }

        ListView virtualList = new ListView();
        virtualList.Columns.Add("Column");
        virtualList.Dock = DockStyle.Fill;
        virtualList.View = View.Details;
        virtualList.VirtualMode = true;
        virtualList.SmallImageList = imageList;
        virtualList.RetrieveVirtualItem += (s, e) =>
        {
            e.Item = new ListViewItem();
            e.Item.Text = "Item " + e.ItemIndex.ToString();
            e.Item.ImageKey = "key";
        };
        virtualList.VirtualListSize = 100;

        SplitContainer split = new SplitContainer();
        split.Dock = DockStyle.Fill;
        split.Panel1.Controls.Add(normalList);
        split.Panel2.Controls.Add(virtualList);
        this.Controls.Add(split);

        split.SplitterDistance = split.Width / 2;
    }
}
Matthew King
  • 5,114
  • 4
  • 36
  • 50
  • 3
    I suppose that you should post your ListView code – Luke Marlin Apr 08 '13 at 09:21
  • @Luke - Good point. I've posted the smallest complete example I could think of that illustrates the problem. – Matthew King Apr 08 '13 at 09:52
  • 1
    possible duplicate of [How to show icon on all listview items in virtual mode (C#)](http://stackoverflow.com/questions/5712164/how-to-show-icon-on-all-listview-items-in-virtual-mode-c) – Serge Wautier Apr 08 '13 at 13:09
  • Possible duplicate of [How to show icon on all listview items in virtual mode (C#)](https://stackoverflow.com/questions/5712164/how-to-show-icon-on-all-listview-items-in-virtual-mode-c) – mja Jun 18 '17 at 02:48

2 Answers2

4

I know this an old question, but for sake of someone looking for this:

In Virtual mode, item.ImageKey will not work. Use item.ImageIndex instead. ImageList.ImageCollection has a IndexOfKey() method to convert the key into index.

    virtualList.RetrieveVirtualItem += (s, e) =>
    {
        e.Item = new ListViewItem();
        e.Item.Text = "Item " + e.ItemIndex.ToString();
        e.Item.ImageIndex = imagelist.Images.IndexOfKey("key");
    };
1

How can this work at all with ListView controls and ImageList being local variables of the c'tor? Does it work any better if they are member of the VirtualListViewExample class ?

UPDATE: My suggestion above is plain wrong. See duplicate question for a workaround to this issue.

Community
  • 1
  • 1
Serge Wautier
  • 21,494
  • 13
  • 69
  • 110
  • The code presented was just a *simple example* to explain my problem. It does not make any difference; why do you think it would? – Matthew King Apr 08 '13 at 10:17
  • Because the variables go out of scope as soon the c'tor finishes, which is even before the controls they map get displayed. If it works even a little bit, that's pure luck due to some inners of the disposable objects and/or the gargabe collector. First thing to do is confirm the problem is still present after you turn those variables into class members to make sure their lifetime is ok. – Serge Wautier Apr 08 '13 at 11:55
  • That's not how things work, FYI. Don't get hung up on it. The variables go out of scope, but the objects are still referenced. It has nothing to do with 'pure luck'. Even Visual Studio's form designer does it the same way as my example if you set GenerateMember to false. Anyway, as I said, my original code uses local variables; the code in the question is just a simple example to replicate the problem. – Matthew King Apr 08 '13 at 12:39
  • Oops! My bad! I learned something today ;-) Anyway, your question is a duplicate (see reference in comment to your question). I tested the solution in that question and it seems to work. – Serge Wautier Apr 08 '13 at 13:09