2

私は BindingSource にバインドされた WinForms DataGridView を持っています。これは、100,000 オブジェクトの BindingList にバインドされています。

BindingList<MyObject> myObjectList = new BindingList<MyObject>();
BindingSource bindingSourceForMyObjects = new BindingSource();

bindingSourceForMyObjects.DataSource = myObjectList;
dataGridViewMyObjects.DataSource = bindingSourceForMyObjects;

次のコードを含む DataGridView の CellValueChanged イベントに接続されたイベント ハンドラーがあります。

dataGridViewMyObjects.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Red;
dataGridViewMyObjects.Rows[e.RowIndex].DefaultCellStyle.ForeColor = Color.White;

したがって、ユーザーが行を変更すると、このイベント ハンドラーが起動し、行を赤地に白に変更して、データが変更されたことを示します。これはうまく機能しますが、基になるリストをプログラムで変更する必要がある場合もあり、それらの変更を DataGridView にも反映させたいと考えています。これを実現するために、私のオブジェクト クラスは INotifyPropertyChanged を実装し、BindingSource の ListChanged イベントに接続されたイベント ハンドラーを用意しました。そのイベント ハンドラーのコードは次のようになります。

if (e.ListChangedType == ListChangedType.ItemChanged)
{
    dataGridViewMyObjects.Rows[e.NewIndex].DefaultCellStyle.BackColor = Color.Red;
    dataGridViewMyObjects.Rows[e.NewIndex].DefaultCellStyle.ForeColor = Color.White;
}

これも機能しているため、プログラムで 50 個のオブジェクトを変更すると、DataGridView の行も更新されます。ただし、前に述べたように、100,000 個のオブジェクトを扱っており、800 個を超えるオブジェクトを変更する必要がある場合は、オブジェクトで OnPropertyChanged() をすべて呼び出すため、しばらく時間がかかることがあります。最悪の場合、100,000 個のオブジェクトすべてを変更する必要がある場合、これが発生するまでに 1 分近くかかることがあります。

オブジェクト クラスの内部には、プログラムで「一括」更新 (> 800 オブジェクト) を実行しているときに OnPropertyChanged() 呼び出しのトリガーを回避するために使用するブール変数があります。これにより、オブジェクト プロパティの更新が非常に高速になりますが、双方向バインディングがバイパスされるため、DataGridView 内の対応する行の前色/背景色の値が更新されなくなります。変更されたオブジェクトに対応する行はわかっているので、それらをループして ForeColor/BackColor 値を更新しようとしましたが、この操作が完了するまでに約 1 分かかります。

そのループをラップしてみました...

dataGridViewMyObjects.SuspendLayout();
// loop here
dataGridViewMyObjects.ResumeLayout();

しかし、それはパフォーマンスに違いをもたらすようには見えませんでした。多くの行に対して ForeColor/BackColor を設定するより高速な方法はありますか?それとも、私が見ている速度は、単に私が扱っているデータのサイズの問題ですか?

4

1 に答える 1

2

試してみる1つのことは、変更をループしている間、コントロールの描画を停止するようにWindowsに指示することです。コントロールとその子のペイントを一時停止するにはどうすればよいですか?

class DrawingControl
{
    [DllImport("user32.dll")]
    public static extern int SendMessage(IntPtr hWnd, Int32 wMsg, bool wParam, Int32 lParam);

    private const int WM_SETREDRAW = 11; 

    public static void SuspendDrawing( Control parent )
    {
        SendMessage(parent.Handle, WM_SETREDRAW, false, 0);
    }

    public static void ResumeDrawing( Control parent )
    {
        SendMessage(parent.Handle, WM_SETREDRAW, true, 0);
        parent.Refresh();
    }
}

その場合、コードは次のようになります。

DrawingControl.SuspendDrawing(dataGridViewMyObjects);
// loop here
DrawingControl.ResumeDrawing(dataGridViewMyObjects);
于 2013-01-24T17:10:24.753 に答える