Click here to Skip to main content
15,616,663 members
Articles / Desktop Programming / WTL
Posted 28 Jun 2011


45 bookmarked

WTL Virtual Listview Control

Rate me:
Please Sign up or sign in to vote.
4.75/5 (24 votes)
28 Jun 2011CPOL3 min read
A data-bound extension of the Windows listview control for WTL.


This is an extension to CListViewCtrl for WTL (Windows Template Library). It supports exchange of most OLEDB datatypes (excluding blob types) between an OLEDB source and a virtual listview control placed in a view window or on a dialog. It was developed and tested with MS SQL Server but should work with any OLEDB accessible database.

Sample application using a view window

Development environment

This template is compatible with WTL 8.0 and the samples were created in Visual Studio 2008. However, earlier versions of WTL and VS should be supportable with minor modifications.


The WTLVirtualList interfaces an OLEDB consumer to an owner-supplied data (LVS_OWNERDATA) report-style listview control. A handler provides data in response to LVN_GETDISPINFO messages. This control dynamically creates listview columns using the consumer-supplied column names and displays an in-place edit control in response to a double click on a subitem. It supports bookmarks for row identification and manipulation, and provides menu handlers for common operations such as move, add, and delete. Column data editing is accomplished with an in-place edit control.

Using the code

The starting point for using this class in your application is generating an OLEDB consumer class for your database table. See Introduction to WTL OLEDB Database Applications for details on how to create an OLEDB consumer class using the ATL Object Wizard. Make a few simple modifications to your consumer class as outlined below to support the bookmark function. Download the sample projects and consult the Titles.h or Customers.h fils if you need assistance.

  1. Add CBookmark<4> m_Bookmark; and DBSTATUS m_dwBookmarkStatus; as member variables
  2. Add pPropSet->AddProperty(DBPROP_IRowsetLocate, true, DBPROPOPTIONS_OPTIONAL); to the GetRowsetProperties function
  3. Add BOOKMARK_ENTRY_STATUS(m_Bookmark, m_dwBookmarkStatus) to the column map

Add a member variable to MainFrm or MainDlg

After your consumer is created and modified, you need to add the WTLVirtualList header to your project and add the CWTLVirtualList<Cxxxxx> m_view; member variable (replace xxxxx with your consumer class name) to your dialog or frame. Initialization for a view window is handled automatically but make sure you add REFLECT_NOTIFICATIONS() to the main frame message map.

Dialog-based applications

You need to add a listview control to your dialog using the resource editor and then place the following code in OnInitDialog to initialize the virtual listview.

// Initialize the virtual list view

// Set first visible column width. Needed because the default
// width is set to the control's width on the dialog
int col = 0;
if (!m_view.GetShowBookmarks()) col = 1;
m_view.SetColumnWidth(col, LVSCW_AUTOSIZE_USEHEADER);

// Set the background color of alternating rows

Menu or button mapping

You'll also want to add command handlers to the message map and, if needed, overridden event handlers for the data commands. As noted above, the virtual list class contains a set of default menu identifiers and event handlers in CLVMenuCommands that handle ordinary data functions. You would need to override the default handler if you need to set key and/or default values when inserting a new record. For example:

LRESULT OnDataNew(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
    m_view.m_data.ClearRecordMemory(); // Sets all values to 0

    // Example of how to set your own data values. Make sure to initialize any
    // key values and non-null fields before Insert is called. After this, non-
    // mandatory values can be entered in the listview for each column
    TCHAR* CustomerID = _T("ZZ997"); // dummy key value
    _tcsncpy_s(m_view.m_data.m_CustomerID, _tcslen(CustomerID) + 1, CustomerID, _TRUNCATE);

    // Call the base handler to do the actual insert
    return m_view.OnDataNew(wNotifyCode, wID, hWndCtl, bHandled);


  • Get/SetBarColor - color of alternating data rows. Choices are NOBAR, BLUEBAR, GRAYBAR, GREENBAR, and REDBAR, but you can add any color you want to the enum.
  • Get/SetReadOnly - data can be modified or not.
  • Get/SetShowBookmarks - a bookmark is an internal row ID. This ID is limited to the consumer presentation and is independent of any key values in the data.
  • Get/SetSingleSelect - one row or multiple rows can be selected.

Under the covers

WTLVirtualList uses a handler for the LVN_GETDISPINFO notification to synchronize on-screen data display with fetches of data from the data source and a conversion function (OledbToString) to format the data for display in the list view. Initial load and scrolling are common triggers for the data fetch.

// This function is called when the list needs database data for items
// that are displayed in the visible portion of the virtual list
    if (pNMHDR->hwndFrom != m_hWnd) return 0;

    // Clear the list if a data acquisition error is encountered.
    if (!IsValidRow()) return SetRowCount();

    // Create a pointer to the item that needs data
    LVITEM* pItem = &((NMLVDISPINFO*)pNMHDR)->item;
    if (pItem->mask & LVIF_TEXT)
        // Obtain the data for the virtual listview control
        if (pItem->iSubItem == 0) // Bookmark
            ULONG row = SetActiveRow(pItem->iItem);
            _ltot_s(row, pItem->pszText, MAXOLEDBNUM, 10);
        else OledbToString(m_prgBindings[pItem->iSubItem], pItem->pszText); // Data

    return 0;

A handler for NM_CUSTOMDRAW paints alternate row colors and could be extended to support other visual trinkets. Also, there are handlers for mouse clicks, edit control, and scroll bars to provide support for those functions.

About the samples

The dialog application uses the titles table from the Pubs database while the view application uses customers from Northwind. You will either need access to a database server with these databases to use the samples or generate a consumer class for your specific table and add it to the project. You may also need to modify the connection string in the consumer classes to point to your database. They are currently set to localhost with Integrated Security.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Written By
Founder Choycer
United States United States
Ed has over 40 years experience in computer technology and a bachelor's degree in Business Administration. He's currently a marketing technology consultant. During his career, he's led software development departments and created software still in use in the communications and healthcare industries. Ed is a veteran of the United States Army. He lives in Arizona in the United States.

Find Ed on Linkedin.

This material is copyright 2019 by Ed Gadziemski. Unauthorized use is strictly prohibited. All rights reserved.

Comments and Discussions

QuestionVery nice! Pin
f-v-g13-Oct-14 21:15
f-v-g13-Oct-14 21:15 
AnswerRe: Very nice! Pin
Ed Gadziemski14-Oct-14 8:19
professionalEd Gadziemski14-Oct-14 8:19 
To find a specific item in a listview, use ListView_FindItem. Only works for the first column.

To find a specific database record or records, supply the search specification to the query string sent by the OLEDB consumer.

To find a record in an existing OLEDB rowset, use IRowsetIndex and IRowsetLocate as shown in MSDN's Index Example. Index and Locate must be exposed by the provider. I've heard that MS SQL Server does not, but I never tried so I don't know if that is true.
GeneralRe: Very nice! Pin
f-v-g15-Oct-14 4:05
f-v-g15-Oct-14 4:05 
GeneralMy vote of 5 Pin
Jiří Miklík3-Jun-13 1:32
Jiří Miklík3-Jun-13 1:32 
Questionnice Pin
BillW3315-Jul-11 7:28
professionalBillW3315-Jul-11 7:28 
GeneralMy vote of 5 Pin
OlegKrivtsov12-Jul-11 0:50
OlegKrivtsov12-Jul-11 0:50 
GeneralMy vote of 5 Pin
ltg18316-Jul-11 20:46
ltg18316-Jul-11 20:46 
GeneralGot my 5 Pin
T800G4-Jul-11 10:54
T800G4-Jul-11 10:54 
GeneralMy vote of 5 Pin
Nemanja Trifunovic29-Jun-11 2:42
Nemanja Trifunovic29-Jun-11 2:42 
QuestionGreat article and some old hidden treasures Pin
Randor 29-Jun-11 2:38
professional Randor 29-Jun-11 2:38 
GeneralMy vote of 5 Pin
Pablo Aliskevicius28-Jun-11 23:20
Pablo Aliskevicius28-Jun-11 23:20 
GeneralMy vote of 5 Pin
Alain Rist28-Jun-11 21:27
Alain Rist28-Jun-11 21:27 
GeneralMy vote of 5 Pin
Member 191236728-Jun-11 15:33
Member 191236728-Jun-11 15:33 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.