Processing the WM_NOTIFY Message
A list view control notifies its parent window of events by sending a WM_NOTIFY message. The wParam parameter is the identifier of the list view control, and the lParam parameter is the address of an NMHDR structure (or to a larger structure that has an NMHDR structure as its first member). The example in this section processes the LVN_GETDISPINFO, LVN_ENDLABELEDIT, and LVN_COLUMNCLICK notification messages.
A list view control sends the LVN_GETDISPINFO notification message to retrieve information about an item or subitem from the parent window. This notification is sent, for example, when an item with the LPSTR_TEXTCALLBACK value needs to be displayed.
A list view control sends the LVN_ENDLABELEDIT notification message when the user completes or cancels editing of an item's label. This notification is only sent if the list view control has the LVS_EDITLABELS window style. If editing is being canceled, the parent window typically does nothing. If editing is being completed, the parent window should set the item label to the new text, unless the item label is LPSTR_TEXTCALLBACK. In that case, the parent window should simply update the application-defined data it maintains for the list item.
If the user clicks a column header in report view, a list view control sends the LVN_COLUMNCLICK notification message. Typically, an application sorts a list view by the specified column when this clicking occurs. To sort, use the LVM_SORTITEMS message, specifying an application-defined comparison function.
The following example shows the portion of the application's window procedure that processes the WM_NOTIFY message.
case WM_NOTIFY:
// Branch depending on the specific notification message.
switch (((LPNMHDR) lParam)->code) {
// Process LVN_GETDISPINFO to supply information about
// callback items.
case LVN_GETDISPINFO:
Main_OnGetDispInfo((LV_DISPINFO *) lParam);
break;
// Process LVN_ENDLABELEDIT to change item labels after
// in-place editing.
case LVN_ENDLABELEDIT:
return Main_OnEndLabelEdit(
(LV_DISPINFO *) lParam
);
// Process LVN_COLUMNCLICK to sort items by column.
case LVN_COLUMNCLICK:
#define pnm ((NM_LISTVIEW *) lParam)
ListView_SortItems(
pnm->hdr.hwndFrom,
ListViewCompareFunc,
(LPARAM) (pnm->iSubItem)
);
#undef pnm
break;
}
break;
The following example shows the application-defined functions that the window procedure uses to process list view notification messages.
// Main_OnGetDispInfo - processes the LVN_GETDISPINFO
// notification message.
// pnmv - value of lParam (points to an LV_DISPINFO structure)
VOID WINAPI Main_OnGetDispInfo(LV_DISPINFO *pnmv)
{
// Provide the item or subitem's text, if requested.
if (pnmv->item.mask & LVIF_TEXT) {
MYITEM *pItem = (MYITEM *) (pnmv->item.lParam);
lstrcpy(pnmv->item.pszText,
pItem->aCols[pnmv->item.iSubItem]);
}
}
// Main_OnEndLabelEdit - processes the LVN_ENDLABELEDIT
// notification message.
// Returns TRUE if the label is changed or FALSE otherwise.
// pnmv - value of lParam (points to an LV_DISPINFO structure)
BOOL Main_OnEndLabelEdit(LV_DISPINFO *pnmv)
{
MYITEM *pItem;
// The item is -1 if editing is being canceled.
if (pnmv->item.iItem == -1)
return FALSE;
// Copy the new text to the application-defined structure,
// a pointer to which is saved as item data.
pItem = (MYITEM *) (pnmv->item.lParam);
pItem->aCols[0] = (PSTR) LocalReAlloc(
(HLOCAL) (pItem->aCols[0]),
lstrlen(pnmv->item.pszText) + 1,
LMEM_MOVEABLE
);
lstrcpy(pItem->aCols[0], pnmv->item.pszText);
// No need to set the item text, because it is a callback item.
return TRUE;
}
// ListViewCompareFunc - sorts the list view control. It is a
// comparison function.
// Returns a negative value if the first item should precede the
// second item, a positive value if the first item should
// follow the second item, and zero if the items are equivalent.
// lParam1 and lParam2 - item data for the two items (in this
// case, pointers to application-defined MYITEM structures)
// lParamSort - value specified by the LVM_SORTITEMS message
// (in this case, the index of the column to sort)
int CALLBACK ListViewCompareFunc(
LPARAM lParam1,
LPARAM lParam2,
LPARAM lParamSort)
{
MYITEM *pItem1 = (MYITEM *) lParam1;
MYITEM *pItem2 = (MYITEM *) lParam2;
// Compare the specified column.
int iCmp = lstrcmpi(pItem1->aCols[lParamSort],
pItem2->aCols[lParamSort]);
// Return the result if nonzero, or compare the
// first column otherwise.
return (iCmp != 0) ? iCmp :
lstrcmpi(pItem1->aCols[0], pItem2->aCols[0]);
}