0
public new int VirtualListSize
    {
        get { return base.VirtualListSize; }
        set
        {
            // If the new size is smaller than the Index of TopItem, we need to make
            // sure the new TopItem is set to something smaller.
            if (VirtualMode &&
                View == View.Details &&
                TopItem != null &&
                value > 0 &&
                TopItem.Index > value - 1)
            {
                TopItem = Items[value - 1];
            }

            base.VirtualListSize = value;
        }
    }

I am trying to set the topitem property of listview, however in virtual mode items are disabled. so any code trying to access it in virtual mode throws an invalidoperation exception. Exception doesn't occur when i try to debug line by line. If i comment the line TopItem=Items[value-1] it doesnt throws any exception.

System.InvalidOperationException: When in VirtualMode the ListView RetrieveVirtualListItem event needs a list view SubItem for each ListView column. at System.Windows.Forms.ListView.WmReflectNotify(Message& m) at System.Windows.Forms.ListView.WndProc(Message& m) at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) Please suggests.

eeshwr
  • 258
  • 4
  • 20

1 Answers1

4

You don't need to change the TopItem when the virtual list size becomes smaller. The .NET ListView already does that. According to dotPeek disassembler:

public int VirtualListSize { 
    ... 
    set {
        ...
        bool keepTopItem = this.IsHandleCreated && VirtualMode && this.View == View.Details && !this.DesignMode; 
        int topIndex = -1;
        if (keepTopItem) { 
            topIndex = unchecked( (int) (long)SendMessage(NativeMethods.LVM_GETTOPINDEX, 0, 0)); 
        }

        virtualListSize = value;

        if (IsHandleCreated && VirtualMode && !DesignMode)
            SendMessage(NativeMethods.LVM_SETITEMCOUNT, virtualListSize, 0); 

        if (keepTopItem) { 
            topIndex = Math.Min(topIndex, this.VirtualListSize - 1); 
            // After setting the virtual list size ComCtl makes the first item the top item.
            // So we set the top item only if it wasn't the first item to begin with. 
            if (topIndex > 0) {
                ListViewItem lvItem = this.Items[topIndex];
                this.TopItem = lvItem;
            } 
        }
    } 
}

This trouble with this is that, in my experience, setting TopItem on a virtual listview is an error prone activity. In my code I have this block:

// Damn this is a pain! There are cases where this can also throw exceptions!
try {
    this.listview.TopItem = lvi;
}
catch (Exception) {
    // Ignore any failures
}

Since setting TopItem sometimes throws exceptions, this means that sometimes setting VirtualListSize similarly throws exceptions.

Other points

You can access the Items collection via an index even when in virtual mode. So, this is fine (assuming the list isn't empty):

this.listview1.TopItem = this.listview1.Items[this.listview1.Items.Count - 1];

You can't iterate the Items collection in virtual mode. This will throw an exception:

foreach (ListViewItem item in this.listview1.Items) { ... }
Grammarian
  • 6,774
  • 1
  • 18
  • 32
  • Seems like my code is fine TopItem = Items[value - 1]; . But it stills throws exception and i could not catch the exception. I couldn't find where it came from. but when ever i comment this line `TopItem = Items[value - 1];` it works fine. But if i debug the code line by line it does not throw any excpetion. System.InvalidOperationException: When in VirtualMode the ListView RetrieveVirtualListItem event needs a list view SubItem for each ListView column. – eeshwr Feb 10 '15 at 05:51
  • 1
    That exception is raised when your RetrieveVirtualListItem handler returns an incomplete ListViewItem. I would guess your handler has a logic error. – Grammarian Feb 10 '15 at 22:26
  • thank you for your help, I will check the logic of the handler – eeshwr Feb 11 '15 at 05:18
  • I've a question, why was the exception not raised when i remove the line TopItem = Items[value - 1] ?? – eeshwr Feb 12 '15 at 05:12
  • 1
    Since your listview is virtual, the code `Items[value - 1]` causes the `RetrieveVirtualListItem` to be triggered. Take away that line and the event is not raised. – Grammarian Feb 12 '15 at 12:04
  • Thank you for your help. I checked the code and found that RetrieveVirtualListItem handler is not creating subitems for the item. – eeshwr Feb 13 '15 at 07:52