Loading large amounts of data into a CListView derived class is a very slow process, even when the data is maintained in memory. Accessing data in a database slows the process down even further. One of new features of a list view control is the ability to load data when it is needed. Below are the steps envolved.

You must have a version of COMCTL32.DLL that came with IE 3.0 or later.

Open up you database file.

Use your document object to open your database, and record set. In this example I use a dynaset type recordset. This allows me to set the relative record number of a recordset object's current record by using CDaoRecordSet's SetAbsolutePosition member function. Pass the a pointer to the recordset to your view class in an appropriate manner.

BOOL CVirtualListDoc::OnOpenDocumentFile(LPCTSTR lpszPathname){ CString m_FileName = lpszPathname; pDBase = new CDaoDatabase; pDBase->Open(m_FileName); CString strSQL = "SELECT * FROM TableName ORDER BY ColumnName";//Set up SQL statement pRecordSet = new CDaoRecordset(pDBase); pRecordSet->Open(dbOpenDynaset, strSQL);
//Open recordset using SQL statement pRecordSet->MoveLast();
//you have to access the records in the dynaset to get GCDaoRecordSet::etRecordCount() to work}


Set the ListView's style to LVS_OWNERDATA:

BOOL CVirtualListView::PreCreateWindow(CREATESTRUCT& cs){ cs.lpszName = WC_LISTVIEW; cs.style &= ~LVS_TYPEMASK; cs.style |= LVS_REPORT; cs.style |= LVS_EDITLABELS; cs.style |= LVS_OWNERDATA; CListView::PreCreateWindow(cs);}


Set number of items in list:

You have to tell the list view how many items it will contain. This is done by sending a LVM_SETITEMCOUNT to the list control. Do this and set up the list views columns in the views OnInitialUpdate() member function. You can send a LVM_SETEXTENDEDLISTVIEWSTYLE message to the control to set any of the new extended listview styles.

void CVirtualListView::OnInitialUpdate(){ CListView::OnInitialUpdate(); /*set number of items in list to number of items in RecordSet*/  /* create image list*/ imageList.Create(IDB_IMAGELIST, 16, 1, RGB(0,0,0)); GetListCtrl().SetImageList(&imageList, LVSIL_SMALL); /* set extended stlyes*/ DWORD dwExStyle = LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | /*LVS_EX_SUBITEMIMAGES |*/      LVS_EX_HEADERDRAGDROP | LVS_EX_TRACKSELECT; GetListCtrl().SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LPARAM(dwExStyle));  LV_COLUMN lvColumn; lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = 120; for(int i = 0; i < GetFieldCount(); i++) // set up columns {  CDaoFieldInfo fieldinfo;  pRecordSet->GetFieldInfo(i, fieldinfo);//get field name  int len = fieldinfo.m_strName.GetLength();  CString temp = fieldinfo.m_strName;  TCHAR* szBuffer = new TCHAR[len + 1];  strcpy(szBuffer, temp.GetBuffer(len));  temp.ReleaseBuffer();  lvColumn.pszText = szBuffer;  GetListCtrl().InsertColumn(i, &lvColumn);//insert column  delete szBuffer; } /*set number of items in ListView*/ count = pRecordSet->GetRecordCount();//Get number of records GetListCtrl().SendMessage(LVM_SETITEMCOUNT, (WPARAM)count, (LPARAM)LVSICF_NOINVALIDATEALL);}


Create a handler to handle LVN_GETDISPINFO messages:

void CVirtualListViewView::OnGetDispInfo(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; TCHAR szValue[MAX_PATH]; COleVariant varValue;   long index = pDispInfo->item.iItem; long subItem =  pDispInfo->item.iSubItem; if(pDispInfo->item.mask & LVIF_TEXT) {  try  {   pRecordSet->SetAbsolutePosition(index);
//Set the file to desired index  }  catch(CDaoException* e)  {   return;    }    try  {   if(subItem)     pRecordSet->GetFieldValue(subItem, varValue);   else    pRecordSet->GetFieldValue(0, varValue);  }  catch(CDaoException* e)  {   return;  }  const VARIANT* variant = LPCVARIANT(varValue);  switch(variant->vt)  {   case VT_I2:{ wsprintf(szValue, "%d", variant->iVal);       break;        }   case VT_I4:{ wsprintf(szValue, "%d", variant->lVal);       break;        }   case VT_R4:{ wsprintf(szValue, "%f", variant->fltVal);       break;        }    case VT_R8:{ wsprintf(szValue, "%f", variant->dblVal);       break;        }   case VT_CY:{ COleCurrency c(varValue);       CString s = c.Format();//ie. 1.00       strcpy(szValue, s.GetBuffer(s.GetLength()));       s.ReleaseBuffer();       break;        }   case VT_DATE:{ COleDateTime t(variant->date);       CString s = t.Format( "%A, %B %d, %Y" );
//Day of Week, Month Day, Year       strcpy(szValue, s.GetBuffer(s.GetLength()));       s.ReleaseBuffer();       break;       }   case VT_BSTR:{  CString str = V_BSTRT( &varValue );
//convert BSTR to CString       strcpy(szValue, str.GetBuffer(str.GetLength()));       str.ReleaseBuffer();       break;      }   case VT_BOOL:{ if(variant->boolVal)        strcpy(szValue, "TRUE");       else        strcpy(szValue, "FALSE");       break;       }   case VT_UI1:{ strcpy(szValue, (char*)variant->bVal);       break;      }   default: break;  }    lstrcpyn(pDispInfo->item.pszText, szValue, pDispInfo->item.cchTextMax);
//set item text }  if(pDispInfo->item.mask & LVIF_IMAGE)  pDispInfo->item.iImage = 0;
//set image to first in list *pResult = 0;}