Virtual DataGridView mode with a simple list as a source

I used to ask a question about my dataGridView performance due to the fact that it displayed a large number of rows that are added based on the input stream. Several solutions were provided, one of which allows the use of virtual mode. MSDN has an article on this, but it seems more complex than what I need, as it uses a database and an editable field. My DataGridView is for display only, and the displayed data is put into a list.

After I accepted the answer, I got this link: http://www.codeproject.com/Articles/23937/Paging-Data-with-DataGridView-in-VirtualMode . Although this uses a sample database, it is better suited for what I need. My list, which will contain the data that I want to display, is declared as follows:

List<ResultRow> captureResults = new List<ResultRow>(); 

A ResultRow object is defined as follows:

 /* Simplified */ public class ResultRow { private int first = 0; private string second = ""; private UInt64 third = 0; private IPAddress fourth = null; /* etc */ public ResultRow() { } public void Set (<the values>) //In actuallity a KeyValuePair { //field gets set here } public UInt64 Third { get { return third; } set { third = value; } } /* etc. */ 

}

Following the above article, I created ResultRowCache. The object is made as follows:

 /* Page size set to 100. */ ResultRowCache _cache = new ResultRowCache(PAGE_SIZE, captureResults); 

In my form, Download an event I do the following (related to this problem. I also added an event handler, although this is done using the IDE, so it is not directly shown in this code. Definition below!)):

 dataGrid.VirtualMode = true; _cache = new ResultRowCache(PAGE_SIZE, captureResults); dataGrid.Columns.Add("FirstColumn" , "First column header"); dataGrid.Columns.Add("Second Column", "Second column header"); /* Etc. Adding all columns. (Every member or ResultRow has it own column. */ dataGrid.RowCount = (int)_cache.TotalCount; 

I am wondering how the RowCount is initialized here. This is probably 0 (due to a call to the ResultRowCache constructor (see below)), but it never changes. Does this designation as a reference? How does this happen?

In any case, starting with what I have, ResultRowCache is defined as follows:

 public class ResultRowCache { public int PageSize = 100; public long TotalCount; public List<ResultRow> CachedData = null; private List<ResultRow> FullData; int _lastRowIndex = -1; public ResultRowCache (int pageSize, List<ResultRow> total) { PageSize = pageSize; FullData = total; LoadPage( 0 ); } public void LoadPage (int rowIndex) { int lastRowIndex = rowIndex - ( rowIndex % PageSize ); /* Page already loaded */ if( lastRowIndex == _lastRowIndex ) return; /* New page */ _lastRowIndex = lastRowIndex; /* Create a new cashes data object */ if( CachedData == null ) CachedData = new List<ResultRow>(); /* If cached data already existed, clear */ CachedData.Clear(); /* The index is valid (there is data */ if (lastRowIndex < FullData.Count) { /* Not a full page */ if (lastRowIndex + PageSize > FullData.Count) { CachedData = FullData.GetRange(lastRowIndex, ((lastRowIndex + PageSize) - 1) - FullData.Count); } /* Full page */ else { CachedData = FullData.GetRange(lastRowIndex, PageSize); } } TotalCount = CachedData.Count; } } } 

Finally, my CellValueNeeded event for a datagrid is defined as follows:

 void DataGridCellValueNeededEvent(object sender, DataGridViewCellValueEventArgs e) { _cache.LoadPage(e.RowIndex); int rowIndex = e.RowIndex % _cache.PageSize; switch (dataGrid.Columns[e.ColumnIndex].Name) { /* Not actual names, example */ case "FirstColumn": e.Value = _cache.CachedData[rowIndex].First; break; case "SecondColumn": e.Value = _cache.CachedData[rowIndex].Second; break; /* Rest of the possibly columns/ResultRow values */ } } 

Problem: my datagrid remains empty even if the captureResults list is populated. Here is what I have tried so far:

  • Update the RowCount member of the datagrid after switching in the event.
  • Declare a list with the total number of results in the cache so that it is always updated. (I was afraid that the "external changes" would not go into List i, which is passed in the cached constructor, even if it was a link. (Too new version of C #))
  • Set the RowCount parameter of the datagrid to 100 (hard value) in the form load event.
  • Added a call to "Update ()" in the datagrid after adding something to the captureResults list. (this comes from a special thread that calls a function that adds something to the list)

None of the above has changed anything. The grid remains empty. I think I'm missing something completely obvious here. Any suggestions?

-edit- Added something that I was trying to make it work.

+7
source share
1 answer

I feel that using Cache complicates the process somewhat (although I feel responsible after sending you a link to msdn, which is implemented in this way).

As a starting point, I would recommend the following:

  • Drop the cache (this may be useful later if you run into memory problems, but now let's just load your datagrid)

  • Save the List<ResultsRow> in the instance variable.

  • Make sure dataGrid.VirtualMode = true; (or equivilant)

  • Implement CellValueNeeded as follows:

      private void gridContacts_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) { ResultRow dataObject = resultRows[e.RowIndex]; switch(e.ColumnIndex) { case 0: e.Value = dataObject.First; break; case 1 : e.Value = dataObject.Second; break; //etc.. } } 

Note. In DataObject, you will need to set some additional public properties so that they can be set as values ​​in the method.

See how you handle this. If you set some breakpoints in the CellValueNeeded method, which should help in debugging any further unexpected behavior. Good luck.

+2
source

All Articles