Click here to Skip to main content
Click here to Skip to main content
Go to top

WTL Virtual Listview Control

, 28 Jun 2011
Rate this:
Please Sign up or sign in to vote.
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Ed Gadziemski
Founder KwikiVac
United States United States
Ed has over 40 years experience in computer technology and a bachelor's degree in Business Administration. He currently owns an online retail business and previously owned a software consulting firm. During his career, he has 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.
 
This material is copyright 2014 by Ed Gadziemski. Unauthorized use is strictly prohibited. All rights reserved.

Comments and Discussions

 
GeneralMy vote of 5 PinmemberJiří Miklík3-Jun-13 1:32 
Questionnice PinmemberCIDev15-Jul-11 7:28 
A clearly written article and a nice control.
Just because the code works, it doesn't mean that it is good code.

GeneralMy vote of 5 Pinmemberzexspectrum12-Jul-11 0:50 
GeneralMy vote of 5 Pinmemberltg18316-Jul-11 20:46 
GeneralGot my 5 PinmemberT800G4-Jul-11 10:54 
GeneralMy vote of 5 PinmemberNemanja Trifunovic29-Jun-11 2:42 
QuestionGreat article and some old hidden treasures Pinmember Randor 29-Jun-11 2:38 
GeneralMy vote of 5 PinmemberPablo Aliskevicius28-Jun-11 23:20 
GeneralMy vote of 5 PinmemberAlain Rist28-Jun-11 21:27 
GeneralMy vote of 5 PinmemberMember 191236728-Jun-11 15:33 

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

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

| Advertise | Privacy | Mobile
Web03 | 2.8.140916.1 | Last Updated 28 Jun 2011
Article Copyright 2011 by Ed Gadziemski
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid