3

外部システムから受信したデータを表示する必要があるアプリケーションを構築しています。このデータは、すべての行が占有するバイト数が比較的少ない場合でも、非常に迅速に取得できます。これは、時間単位ごとに多くの行を追加する必要があることを意味します。私は現在、処理できるよりも速くデータを受信して​​いるように見えるところにいます。つまり、メモリ使用量が増えています。

これの大部分は、実際の dataGridView の描画に関係していると思います。パフォーマンスが向上することを期待して、dataGridView を少し調整しました。(例: 自動サイズの無効化、特別なスタイルなど)

最近の追加で、必要な行の色を追加しました。現在、私のアプリケーションは次のように機能します。

  1. 外部システムからデータを受け取ります
  2. スレッドによってキュー (ConcurrencyQueue) にデータを配置します
  3. 別のスレッドがそのキューからデータを取得して処理し、テーブルにバインドされている BindingList に追加します。

実際の追加は、2 つのパラメーターを持つ関数で行われます。 1. 列の項目を含むリスト (項目) 2. 行の色 (色)

次のようになります (半疑似)。

/* Store the color for the row in the color list so it is accessible from the event */  

rowColors.Add(rowColor);    //Class variable that stored the colors of the rows used in the DataGridCellFormatting event

/* Create the row that is to be added. */
ResultRow resultRow = new ResultRow();

foreach(item in items)
{
    resultRow.Set(item); /* It's actually a dictionary because some fields are optional, hence this instead of a     direct constructor call) */
}

bindingList.Add(resultRow);

/* Row coloring based on error is done in the OnCellFormatting() */


/* Auto scroll down */
if (dataGrid.Rows.Count > 0)
{
    dataGrid.FirstDisplayedScrollingRowIndex = dataGrid.Rows.Count - 1;
}

上記のコードに見られるように、受け取った色は、次のように datagridview のイベントで使用されるリストに追加されます。

void DataGridCellFormattingEvent(object sender, DataGridViewCellFormattingEventArgs e)
{
    // done by column so it happens once per row
    if (e.ColumnIndex == dataGrid.Columns["Errors"].Index)
    {
        dataGrid.Rows[e.RowIndex].DefaultCellStyle.BackColor = rowColors[e.RowIndex];
}
} 

BindingList は次のように定義されます。

BindingList bindingList;

ここで、ResultRow は次のような構造を持つクラスです。

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

パフォーマンスを向上させるためにできる比較的簡単なことはありますか? 処理がビジーである間はデータグリッドの描画を無効にし、完了したら描画することを考えていました。(好まれませんが) もう 1 つのことは、アイテムを受け取るたびに更新するのではなく、更新頻度を下げることです。(ただし、BindingList は、何かが追加されると DataGridView を自動的に更新するようです)

誰かが喜んで/できることを願っています。

-編集-

フォームの応答性は、特にしばらくしてから上記の方法でデータを処理しているときも同様に非常に悪いためです。(上記のプロセスはバックグラウンド ワーカーとバックグラウンド スレッドで行われますが)

4

2 に答える 2

5

グリッド内の行数が非常に多いため、しばらくするとパフォーマンスが低下する場合があります。仮想モードを試してみてください。

ただし、最初に、グリッドの更新を延期し、新しいエントリをバッチで追加してみてください。つまり、更新頻度を減らします。したがって、各バッチ更新の前に:

// stop raising update events
bindingList.RaiseListChangedEvents = false; 

そしてその後:

// restore update events, raise reset event
bindingList.RaiseListChangedEvents = true;
bindingList.ResetBindings() 

最後の行の後、最後の行までスクロールを続けます。

于 2012-05-08T08:25:02.980 に答える
0

はい、それをスピードアップするためにできることがいくつかあります。

まず、データグリッドを仮想化します。これは、表示されるデータ項目の行のみを入力し、クライアント領域を描画する winforms データグリッドへの組み込みメカニズムです。したがって、コントロールが 20 行 (および他のスクロールバー) のみを表示している場合、実際には 20 項目のみが UI としてデータグリッドに処理されます。次に、グリッドをスクロールして他の項目を表示すると、データグリッドが入力され、要求された行がオンデマンドで表示されます。これには少し手を加える必要があり (CellValueNeeded イベントをサブスクライブする必要があります)、bindingsource データ項目を編集する必要がある場合があります。詳細については、 http://msdn.microsoft.com/en-us/library/ms171622.aspxを参照してください。

2 番目にできることは、データの「チャンク」に入力している間、UI の更新を一時停止することです。既に示したように、項目をグリッドに追加すると、bindinglist は自動的にグリッドを更新します。ただし、UI の更新を一時停止し、一定の間隔 (たとえば 1 秒ごと) で再度有効にすることで、データのストリーミング速度が一定ではなくなります。ただし、データに対して同じ処理を行う必要があるため、これでデータが完全に解決される可能性は低く、画面のちらつきを減らすのにより効果的である可能性があることに注意してください。詳細についてはControl.SuspendLayout()、 およびControl.ResumeLayout()を参照してください。

私の意見では、仮想化は非常に大きなデータセットのグリッド機能を改善することだけを目的としているため、最も効果的なツールになるでしょう。

于 2012-05-08T08:18:55.873 に答える