WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

Just-In-Time Data Loading For DataGrids
Pages: 1, 2, 3, 4, 5, 6

DataGridView Events

The only event you need to handle for the grid is CellValueNeeded, which will be called every time the grid wants to draw a cell for any reason (typically because a row has scrolled into view).



private void dgvJIt_CellValueNeeded( 
   object sender, DataGridViewCellValueEventArgs e )
{
   e.Value = memoryCache.RetrieveElement( e.RowIndex, e.ColumnIndex );
}

You handle the event by calling the RetrieveElement method on your Cache, passing in the row and column. As far as the grid is concerned, it is up to the cache to supply the data to put in the cell; how it does so is fully encapsulated in the methods of the Cache class. The only interface to that class, from the application, is through this single method: RetrieveElement.

The Cache Class

The Cache class is pretty big and most of the code is "housekeeping," so I won't show it all here. Feel free to download the full source code, and I'll just review the highlights here.

Note: the Cache and DataRetriever classes are only minimally changed from the Microsoft walk-through available in the MSDN documentation.

The Cache class has a static member variable RowsPerPage and a nested struct DataPage. The DataPage struct represents (surprise!) a page of data, and has three private members: a reference to a DataTable and two integers, representing the lowest index value and the highest index value, respectively.

The key to understanding the cache is in the RetrieveElement method, which takes as arguments the row and column whose value you want to retrieve:

public string RetrieveElement( int rowIndex, int columnIndex )
{
   string element = null;

   if ( IfPageCached_ThenSetElement( rowIndex, columnIndex, ref element ) )
   {
      return element;
   }
   else
   {
      return RetrieveData_CacheIt_ThenReturnElement(
          rowIndex, columnIndex );
   }
}

RetrieveElement calls the private method IfPageCached_ThenSetElement which looks to see if the element is in either of the Cache's two cached pages. It returns true if the element is cached. (The element itself is returned as a reference parameter.)

private bool IfPageCached_ThenSetElement( int rowIndex,
    int columnIndex, ref string element )
{
   if ( IsRowCachedInPage( 0, rowIndex ) )
   {
      element = cachePages[0].table
          .Rows[rowIndex % RowsPerPage][columnIndex].ToString();
      return true;
   }
   else if ( IsRowCachedInPage( 1, rowIndex ) )
   {
      element = cachePages[1].table
          .Rows[rowIndex % RowsPerPage][columnIndex].ToString();
      return true;
   }

   return false;
}

If IfPageCached_ThenSetElement returns false, then the element is not in the cache, so RetrieveElement calls RetrieveData_CacheIt_ThenReturnElement, which asks the DataRetriever object (stored by the Cache when it was constructed) to get a new page of data, caches the new page, and then calls RetrieveElement to return the newly cached data.

 private string RetrieveData_CacheIt_ThenReturnElement(
     int rowIndex, int columnIndex )
 {
    // Tell the DataRetriever to give back a page of data
    DataTable table = dataSupply.SupplyPageOfData(
        DataPage.MapToLowerBoundary( rowIndex ), RowsPerPage );

    // Replace the cached page furthest from the requested cell
    // with a new page containing the newly retrieved data.
    cachePages[GetIndexToUnusedPage( rowIndex )] = new DataPage( table, rowIndex );

    return RetrieveElement( rowIndex, columnIndex );
 }

Pages: 1, 2, 3, 4, 5, 6

Next Pagearrow