Why is there an LVN_ODSTATECHANGED notification when there’s already a perfectly good LVN_ITEMCHANGED notification?


If you work with owner-data listviews, you take the responsibility for managing the data associated with each item in the list view. The list view control itself only knows how many items there are; when it needs information about an item, it asks you for it. It’s the fancy name for a “virtual list view” control.

When you use an ownerdata list view, you will receive a new notification, LVN_ODSTATECHANGED. The OD stands for ownerdata, so this is an “owner data state changed” notification. The list view sends this notification when the state of one or more items in an owner data list view control change simultaneously. Mind you, the list view control can also send the LVN_ITEMCHANGED notification if the state of an item changes, so you need to be on the lookout for both.

If there is a notification LVN_ITEMCHANGED, then what’s the purpose of the LVN_ODSTATECHANGED message? It’s redundant, after all.

Well yes, it’s redundant, but it’s faster, too. The LVN_ODSTATECHANGED notification tells you that the state of all items in the specified range has changed. It’s a shorthand for sending an individual LVN_ITEMCHANGED for all items in the range [iFrom..iTo]. If you have an ownerdata list view with 500,000 items and somebody does a select-all, you’ll be glad that you get a single LVN_ODSTATECHANGED notification with iFrom=0 and iTo=499999 instead of a half million individual little LVN_ITEMCHANGED notifications.

Comments (4)
  1. Adam Rosenfield says:

    If you have a listview with 500,000 items in it, that's quite a usability nightmare!  Of course, your point still stands for a much more reasonable size like 5,000 items.

  2. peterchen says:

    @Adam Rosenfield: Not if you provide some "instant filter", e.g. typing a filter term will reduce the list.

  3. Ivo says:

    It would be very useful if this message is sent even for regular controls (not owner-data). Imagine if you have to update the selection count like Explorer does in the status bar. If you do that on LVN_ITEMCHANGED, you will have to update it many times after a "select all". With a single message like LVN_ODSTATECHANGED (or a new one LVN_SELCHANGED) life would be much easier.

    What I've done in the past was to post a private message on the first LVN_ITEMCHANGED and set a flag that stops further messages from being posted until the first message is received and processed. It works OK, but if it was done by the list control it would be more efficient.

  4. asf says:

    I had to deal with these two messages the other day, if you look at the structs the OD struct maps pretty good to the other struct so I did:

    //deal with other changes?…

    if (LVIF_STATE&pNMLV->uChanged) {

    NMLVODSTATECHANGE*pLVSC=(NMLVODSTATECHANGE*)pNMLV; //NMLVODSTATECHANGE is much smaller

    pLVSC->iTo=pNMLV->iItem; //ok as long as LVN_ODSTATECHANGED is able to deal with iTo==-1

    pLVSC->iFrom=(-1==pLVSC->iTo)?0:pLVSC->iTo;

    goto "handle_LVN_ODSTATECHANGED";

    }

    A very weird bug I ran into while doing this was that sometimes NMLISTVIEW.iItem would be 16 in a list with 3 items. So I had to deal with both -1 and >myItemCount

Comments are closed.