Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

WTL Virtual Listview Control

0.00/5 (No votes)
28 Jun 2011 1  
A data-bound extension of the Windows listview control for WTL.

Introduction

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.

Background

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
m_view.Init(GetDlgItem(IDC_LIST1));

// 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
m_view.SetBarColor(BLUEBAR);

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);
}

Properties

  • 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
LRESULT OnLVGetDispInfo(int, LPNMHDR pNMHDR, BOOL&)
{
    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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here