2009-08-18 17 views
1

デリゲートを使用してメインコントロールスレッドのコントロールを更新する方法を理解しました。これは魅力的です。私の問題は、DataGridViewに大量のDataSet(2000アイテム)を追加すると、グリッドがポピュレートするのに5〜8秒かかり、その間5〜8秒でGUI全体がロックされてしまうのです。 DataGridViewがユーザーインターフェイスをロックしないように更新するにはどうすればよいですか?DataGridViewへのノンブロッキング更新

明確にするため、問題は、私は、データベースに遅いクエリをやってるし、UIがその上でブロックされていることを、私はすでにDataSet object[]DataGridがあるBindingList<object>にオブジェクトの配列を追加していませんこれにバインド:

BindingList<object> dataProvider = new BindingList<object>(); 
DataGridView gridView = new DataGridView(); 
gridView.DataSource = dataProvider; 

// ...stuff happens... 

object[] source = dataSet; //of 2000 items 
foreach (object item in source) { //this foreach blocks 
    dataProvider.Add(item); 
} 

私はdataProvider.Add()をしたデリゲートを作成するように(私は仕事ではないと知っていたが、私は見たい考え出していること)、様々なものを試してみましたが、それはまだしなければならなかったので、それは問題ではありませんでした制御スレッド上で発生します。

最初にBindingListを構築してからgridView.DataSourceを設定することをお勧めします。これは動作しますが(グリッドを即座に更新します)、データを追加する唯一の方法は、別の新しいBindingListを作成し、gridView.DataSource.copyTo()(既存のデータを取得する)を行い、その上に新しいデータを追加してからgridView.DataSourceから新しいBindingListに変更してください。私のリストのオブジェクトは静的ではないので、サーバにデータを非同期でアップロードし、新しいBindingListにそれらをコピーすると問題が発生するため、これは私にとってはうまくいかないでしょう。

答えて

1

GridViewがDataSourceにリンクされている間にレコードを追加しています。つまり、毎回レイアウトを更新します。

DataSourceを最初に埋めて、DataSourceプロパティを設定するのはどうですか?

gridView.DataSource = null; 
...stuff happens... 

object[] source = dataSet; //of 2000 items 
foreach (object item in source) { //this foreach blocks 
    dataProvider.Add(item); 
} 

gridView.DataSource = dataProvider; 

foreachループは、別のスレッドに行くことができるが、私はあなたがそれを必要とするとは思いません。

+0

foreachループは、別のスレッドに行くべきであるが、これはまだ正しい考えです。 – user142350

+0

これはちょっと違いますが、通常のイベントでは通常2000個のアイテムを追加できます。彼らはすでに覚えています。 –

+0

foreachループを別のスレッドに入れようとしましたが、それぞれの.Addがまだ制御スレッド上で発生しているため、foreach全体が制御スレッド上でまだ起きていることを意味しています。 Henkは、すべてのアイテムをBindingListに追加した後、gridView.DataSourceをBindingListに設定した後でインスタント・アップデートを行うようにしています。ここでの問題は、gridViewにアイテムを追加したい場合です。新しいBindingListを作成し、既存のアイテムをすべてコピーして、それに追加する必要があります。これにより、現在のデータで実行中の操作(およびハックのようなもの)が中断されます。 – Shizam

0

BackgroundWorkerを参照してください。私は自分自身についてはほとんど分かりませんが、Googleで少し調べることは、それが良い可能性として明らかにしています。

3

ニックが言ったように、BackgroundWorkerはおそらくあなたの最善の策です。

はここで非常に簡単な例

public partial class Form1 : Form 
{ 
    BackgroundWorker b = new BackgroundWorker(); 

    public Form1() 
    { 
     InitializeComponent(); 
     b.RunWorkerCompleted += new RunWorkerCompletedEventHandler(b_RunWorkerCompleted); 
     b.DoWork += new DoWorkEventHandler(b_DoWork); 
    } 

    void b_DoWork(object sender, DoWorkEventArgs e) 
    { 
     // build dataset here and assigning it to results 
     e.Result = dataset;    
    } 

    void b_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     // assign the dataset you built in DoWork in the gridview and update it 
     dataGridView1.DataSource = e.Result; 
     dataGridView1.Update(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     b.RunWorkerAsync(); 
    } 
} 
+0

これはもう一つの良い提案ですが、既存のDataSourceにデータを追加する代わりに、データを追加するたびにDataSourceを置き換えることが必要です。これは問題です。データソース内のオブジェクトがサーバーにデータをアップロードしているため、各オブジェクトが静的ではないため、BindingList.copyTo()を実行できません。 – Shizam

+0

シザム、これを試しましたか?要素がクラス(構造体ではない)である限り、問題はありません。 –

関連する問題