2012-05-09 49 views
7

以前我問了一個關於我的dataGridView的性能的問題,因爲它顯示大量的基於傳入流添加的行。給出了多個解決方案,其中一個啓用虛擬模式。 MSDN有一篇關於這個主題的文章,但它感覺比我需要的更復雜,因爲它使用數據庫和可編輯字段。我的DataGridView僅用於顯示,我顯示的數據放置在List中。DataGridView虛擬模式與一個簡單的列表作爲源

在我接受答案後,我收到此鏈接:http://www.codeproject.com/Articles/23937/Paging-Data-with-DataGridView-in-VirtualMode。儘管它使用數據庫示例,但它更適合我所需。我的列表將包含我想要顯示如下聲明的數據:

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

一個ResultRow對象的定義如下:

/* 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. */ 

}

繼文章上面提到的,我創建了一個ResultRowCache。對象是由如下:。

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

在我的窗體的Load事件中,我做了以下(與此相關的問題,我還添加了一個事件處理程序,儘管這是一個使用IDE,無法直接顯示在此代碼做了定義)):

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's own column. */ 

dataGrid.RowCount = (int)_cache.TotalCount; 

我想知道的一件事是RowCount是如何在這裏初始化的。它可能是0(由於ResultRowCache的構造函數調用(見下文)),但似乎從未再次發生變化。這項任務是否算作參考?它如何更新?

反正以後與我有什麼,該ResultRowCache定義如下:

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

最後,我爲DataGrid CellValueNeeded事件的定義如下:

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 */ 
    } 
} 

的問題:我的即使「captureResults」列表被填充,datagrid仍爲空。這是我到目前爲止所嘗試的:

  • 更新事件中切換後的datagrid的RowCount成員。
  • 用緩存中的結果總數聲明該列表,以確保它始終處於最新狀態。 (我擔心「外部修改」不會通過緩存的構造函數傳遞給我的列表,儘管它是一個參考。(與C#相同)
  • 將datagrid的RowCount設置爲100(硬值)在窗體的加載事件中。
  • 在向CaptureResults列表添加內容後,向datagrid添加了「Update()」調用。 (這發生在一個特殊的線程中,這個調用的功能會添加一些東西到列表中)

以上都沒有改變任何東西。網格保持空白。我想我錯過了一些很明顯的東西。有什麼建議麼?

-edit-增加了一些我試圖讓它工作的東西。

回答

2

我覺得緩存的使用會讓這個過程變得複雜一些(儘管在發送鏈接到以這種方式實現的msdn之後,我確實感到負責)。

我會建議作爲出發點是:

  1. 扔掉緩存(這可能是有用的以後,如果你遇到內存問題,但現在,讓我們找你的數據網格填充)

  2. 將您的List<ResultsRow>存儲在實例變量中。

  3. 確保dataGrid.VirtualMode = true;(或equivilant)

  4. 實施CellValueNeeded如下:

    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.. 
         } 
        } 
    

注意:您需要在數據對象暴露了一些額外的公共屬性,使他們可以在方法中設置爲值。

看看你如何繼續。如果您在CellValueNeeded方法中設置了一些斷點,這些斷點應該有助於調試任何進一步的意外行爲。祝你好運。

+0

我設法讓它在沒有緩存的情況下工作,通過在每次添加後更新RowCount並使用我的列表大小。然而性能似乎更糟糕。 (也許是因爲我每次增加更新表單,而不是後臺工作人員每隔 ms)我的應用程序在處理完數據後也會相對快速地凍結。這是虛擬模式的錯誤實現還是其他問題? (因爲某些原因,繪製行(可以有不同的背景顏色)對於這個系統來說是非常困難的。我的筆記本電腦(功能更強大)可以更輕鬆地完成這項任務。 – Arnold4107176

+0

您是如何在每次添加後更新RowCount的?分享這段代碼,因爲我不確定它是如何工作的,而且聽起來不太正確。如果將列表分配給bindingSource,然後將其分配給Grid.DataSource,那麼應該充分跟蹤rowCounts和內部列表。 –

+0

啊,我認爲這是我對概念缺乏理解的結果,當我啓用虛擬模式時,我沒有爲DataGridView設置數據源,因爲我認爲這是性能問題,如果我保持這種唯一區別是我將VirtualMode屬性設置爲true,並且定義了CellValueNeeded事件,這是否正確?我不太明白爲什麼這會消除你將會得到的性能。對大型集合來說效率低下的事件的默認實現?用虛擬模式關閉它可能不起作用,我必須閱讀。 – Arnold4107176

相關問題