2012-05-09 20 views
7

以前は、着信ストリームに基づいて追加される大量の行を表示するため、データグリッドビューのパフォーマンスに関する質問をしました。複数のソリューションが提供され、そのうちの1つが仮想モードを有効にしました。 MSDNには件名に関する記事がありますが、データベースと編集可能なフィールドを使用するため、必要以上に複雑です。私のDataGridViewは表示専用で、表示されるデータはListに配置されます。単純なリストをソースとして持つDataGridView仮想モード

私が答えを受け入れた後、私はこのリンクを受けました:http://www.codeproject.com/Articles/23937/Paging-Data-with-DataGridView-in-VirtualMode。それはデータベースの例を使用していますが、私が必要とするものに適しています。私は次のように宣言されて表示するデータが含まれていますマイリスト:

List<ResultRow> captureResults = new List<ResultRow>(); 
次のように

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

次のように最後に、データグリッドのための私の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メンバーを更新します。
  • キャッシュ内の結果の総量をリストに宣言して、常に最新の状態に保つようにします。 (私は恐れていた "外部の変更"は、キャッシュされたコンストラクタに渡されたリストを参照していませんでした) )をフォームのロードイベントに追加します。
  • captureResultsリストに何かを追加した後、DataGridへの "Update()"呼び出しを追加しました。 (これは、Invokeの何かをリストに追加する特別なスレッドから発生します)

上記のどれも変更されていません。グリッドは空のままです。私はここでかなり明白な何かを見逃していると思う。助言がありますか?

-edit-何かを追加しました。動作させるようにしました。

答えて

2

私はキャッシュの使用がプロセスをいくらか複雑にしていると感じています(このような方法で実装しているmsdnへのリンクを送信した後は責任がありますが)。出発点があるように私が推薦する何

  1. キャッシュを捨てる(あなたはメモリの問題に実行するが、今の自分のデータグリッドの移入を取得することができますならば、これは、後に有用である可能性がある)

  2. List<ResultsRow>をインスタンス変数に格納します。

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

注:彼らができるように、DataObjectの中にいくつかの余分なパブリックプロパティを公開する必要がありますが

  • 次のようにdataGrid.VirtualMode = true;(またはequivilant)

  • がCellValueNeededを実装していることを確認してくださいメソッドの値として設定します。

    どのようにそれを乗り越えてください。 CellValueNeededメソッド内にいくつかのブレークポイントを設定すると、予期しない動作のデバッグに役立ちます。がんばろう。

  • +0

    私のリストのサイズを追加するたびにRowCountを更新することで、キャッシュなしで動作させることができました。しかしパフォーマンスは悪化しています。 (私はバックグラウンドワーカーによってms毎にではなく、フォームが毎回更新されるためかもしれません)私のアプリケーションは、データを処理した後も比較的早くフリーズします。それは仮想モードの実装が間違っているのでしょうか、問題は他の場所にありますか? (何らかの理由で、背景色を変えることができます)、このシステムでは非常に難しいのですが、私のラップトップはもっと簡単に操作できます。 – Arnold4107176

    +0

    追加のたびにRowCountを更新する方法は?あなたがリストを、GridSourceに割り当てられるbindingSourceに割り当てると、rowCountsと内部リストを十分に追跡する必要があります。このコードは、このコードを共有しています。 –

    +0

    ああ、これは私のコンセプトの理解の不足の結果だと思う。私はこれがパフォーマンス上の問題であると仮定して、仮想モードを有効にしたときにDataGridViewのデータソースを設定しなかった。私はVirtualModeプロパティをtrueに設定して、CellValueNeededイベントを定義しました。これは正しいですか?これはなぜ、これがパフォーマンスヒットを取るのか分かりません。大きなセットでは非常に効率が悪いイベントのデフォルトの実装ですか?仮想モードでそれを無効にすることはおそらくうまくいかないでしょう、私は読む必要があります。 – Arnold4107176

    関連する問題