35

I want to execute some code when the user selects a row in a CListCtrl (report view, I don't care about the other viewing modes).

How do I catch this event? is there some message I can map or a method like "OnSelectionChanged" or something like that?

LLucasAlday
  • 2,349
  • 11
  • 34
  • 41

4 Answers4

50

Also try:

BEGIN_MESSAGE_MAP(cDlgRun, CDialog)
    ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST2, OnItemchangedList2)
END_MESSAGE_MAP()

/* ... */

void cDlgRun::OnItemchangedList2(NMHDR* pNMHDR, LRESULT* pResult) 
{
    NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

    if ((pNMListView->uChanged & LVIF_STATE) 
        && (pNMListView->uNewState & LVIS_SELECTED))
    {
        // do stuff...
    }
}
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
djeidot
  • 4,542
  • 4
  • 42
  • 45
  • 1
    This will not catch a change when you select three elements with shift, but then select any of them (which deselects the other two, but keeps this one selected). Any workaround for that except keeping a list of selected items? – Kajetan Abt Feb 29 '12 at 17:34
  • I cannot test it right now but I think you will need to catch deselection as well as selection: to catch deselection just use `if ((pNMListView->uChanged & LVIF_STATE) && (pNMListView->uOldState & LVNI_SELECTED) && !(pNMListView->uNewState & LVNI_SELECTED))` – djeidot Feb 29 '12 at 17:50
  • 2
    @djeidot: Thank you very much, it helped. When embedded in its own Control class, this could aso be reduced to ON_NOTIFY_REFLECT(LVN_ITEMCHANGED, &OnItemSelected) – mox Sep 22 '13 at 16:07
  • 1
    @LS_dev don't worry, I'm sure it works. À confiança. – djeidot Oct 30 '13 at 14:53
  • 1
    The `pNMListView->uChanged & LVIF_STATE` condition is very important, because if you don't check, it will do things on undesired moments; in my case i had this triggering when I was doing `SetItemText` – sergiol Dec 14 '16 at 14:57
15

There are a few notifications based on what's happening.

If you are selecting an item and nothing is selected yet, you will get one LVIF_STATE change notification: uNewState & LVIS_SELECTED. The newly selected item will be found at:

pNMListView->iItem

If an item is selected before you select a new object, you'll get three state changes:

First you will be informed that the previous item in focus is losing focus:

pNMListView->uOldState & LVIS_FOCUSED

Then you will be notified that the old item is being unselected:

pNMListView->uOldState & LVIS_SELECTED

Finally, you will get the new item selection state:

pNMListView->uNewState & LVIS_SELECTED

(again look at iItem for newly selected item)

So the pitfall we ran across is that, because item deselection results in two notifications, we were doing a lot of repetitive, sometimes detrimental, processing. What we ended up doing was only doing this processing for the 2nd message (pNMListView->uOldState & LVIS_SELECTED), and skipping the same processing after the loss of focus notification.

The Unfun Cat
  • 29,987
  • 31
  • 114
  • 156
Mark Colbath
  • 151
  • 1
  • 2
  • 1
    Great explanation! It's important to know why the function handling `LVN_ITEMCHANGED` is called multiple times. And interesting that the states `LVIS_FOCUSED` and `LVIS_SELECTED` from the previous item are manipulated separately – ripfreeworld Mar 06 '23 at 15:20
4

djeidot is right on.

I just want to add that there is no OnSelectionChanged() because the ListView supports multi-selection (although this can be disabled). Therefore, a single-selection listview will send you two events: Old item unselected AND New item selected.

Serge Wautier
  • 21,494
  • 13
  • 69
  • 110
0

On my Visual Studio 2010, the visual editor declares a callback in the dialog header file like this:

afx_msg void OnLbnSelchangeListOnvif();

and in the source file:

BEGIN_MESSAGE_MAP(CDialogOnvif, CDialog)
    ON_LBN_SELCHANGE(IDC_LIST_ONVIF, &CDialogOnvif::OnLbnSelchangeListOnvif)
END_MESSAGE_MAP()

void CDialogOnvif::OnLbnSelchangeListOnvif()
{
    // do stuff...
}
Zac
  • 4,510
  • 3
  • 36
  • 44