web-dev-qa-db-ja.com

DataTableを使用してDataGridViewにデータをロードするためのプログレスバー

SQLサーバーデータベースからデータをロードするDataGridViewがあります。データをロードすると、かなり時間がかかります。

データを読み込んでいることをユーザーに知らせたい。データがProgressbarにロードされているときにDataGridViewを接続する最良の方法は何ですか?

完全に機能するコードを誰かに作ってほしくない。それがどうやってできるのか知りたいだけです。

誰かが賞金で私の質問を与えたのを見ます。現時点では、Iamがこのコードを使用していると言います。

DTGdataTable = new DataTable();
SqlDataAdapter SDA = new SqlDataAdapter
SDA.Fill(DTGdataTable);
dataGridView1.DataSource = DTGdataTable ;

皆さん、ありがとうございました。

14
Marek

問題がデータベースからデータをフェッチするのに時間がかかることである場合、私はあなたに可能な解決策を持っています:

    private void buttonLoad_Click(object sender, EventArgs e)
    {
        progressBar.Visible = true;
        progressBar.Style = ProgressBarStyle.Marquee;
        System.Threading.Thread thread = 
          new System.Threading.Thread(new System.Threading.ThreadStart(loadTable));
        thread.Start();
    }

    private void loadTable()
    {
        // Load your Table...
        DataTable table = new DataTable();
        SqlDataAdapter SDA = new SqlDataAdapter();
        SDA.Fill(table);
        setDataSource(table);
    }

    internal delegate void SetDataSourceDelegate(DataTable table);
    private void setDataSource(DataTable table)
    {
        // Invoke method if required:
        if (this.InvokeRequired)
        {
            this.Invoke(new SetDataSourceDelegate(setDataSource), table);
        }
        else
        {
            dataGridView.DataSource = table;
            progressBar.Visible = false;
        }
    }

データをロードするメソッドを別のスレッドに入れ、完了したらデータソースを設定します。必要な呼び出しがあるはずです。プログレスバーにパーセント値を表示したい場合は、スタイル「マーキー」を使用せず、別の関数を追加して、プログレスバーの値を設定するために呼び出すことができるデリゲートを追加します。

データをグリッドにバインドすることが問題である場合、バインドを別のスレッドに入れることができず、別のスレッドで実行される進行状況ポップアップが表示されることがあります。

これがお役に立てば幸いです。

20
Michael

これを試してください...これが最速のルートになるはずです...

1) Add a button control.
2) Add a datagridview control.
3) Add a single column into the datagridview control.
4) Add a progressbar control.
5) Leave them all with default names.

Button1_Clickイベントの下に、このコードのチャンクを追加します...

int maxnumber = 1000;
progressBar1.Value = 0;
progressBar1.Maximum = maxnumber;
for (int x = 0; x <= maxnumber - 1; x++)
{
    Application.DoEvents();
    dataGridView1.Rows.Add(new string[] {Convert.ToString(x)});
    progressBar1.Value += 1;
    label1.Text = progressBar1.Value.ToString();
}

それでおしまい。必要に応じて編集してください。これはあなたが望む完全な正確なコードではありませんが、あなたが始めるのに役立つはずです。プログレスバーの制限を保持するために、maxnumberを自由に宣言しました。あなたの場合、これはデータベースの行数である必要があり、インデックスは常にゼロで始まるので、1から減算されます:)

上記のメソッドはシングルスレッドです。つまり、ループがまだ完了していない間は、マルチタスクを実行できません。場合によっては、コードのアルゴリズムによっては、シングルスレッドメソッドを使用した方がマルチスレッドルートを使用するよりも高速になることがあります。とにかく、2番目の方法は、バックグラウンドワーカーを使用することです。これは、リストがロードされている間もユーザーが処理を実行できるため、最も一般的に好まれています。何かをしている最中でもインストールをキャンセルできるようなインストーラーのようなものです。以下のWebサイトから始めてください。コードはVB.NETにありますが、簡単にC#に変換できます:)

http://social.msdn.Microsoft.com/Forums/vstudio/en-US/efd7510c-43ed-47c4-86a3-1fa350eb0d30/fill-datagridview-using-backgroundworker-progressbar?forum=vbgeneral

3
chris_techno25

コード内では、この行が処理時間のほとんどを占めます。

SDA.Fill(DTGdataTable);

したがって、最も重要なことは、実行中に進捗状況を追跡することです。これを行うには、最初に予想される行数を知る必要があります。 SQLDataAdapterはこの情報を提供できないため、この数値を取得するには、最初に追加のCOUNT(*)クエリを実行する必要があります。これをProgressBarの最大値として使用できます。

私の実際の読み込みコードはMichael Hofmeiersソリューションに基づいていますが、MarqueeモードでProgressBarを使用する代わりに、タイマーコントロールからの実際の進行状況データをフィードします。したがって、フォームにタイマーコントロール(この例ではprogressTimerという名前)を追加し、その間隔を100ミリ秒に設定し、有効をfalseに設定します。コードは次のようになります。

private DataTable table = null;

private void buttonLoad_Click(object sender, EventArgs e)
{
    // TODO: Select the row count here and assign it to progressBar.Maximum

    progressBar.Visible = true;             
    System.Threading.Thread thread = 
      new System.Threading.Thread(new System.Threading.ThreadStart(loadTable));
    thread.Start();
    progressTimer.Enabled = true;
}

private void loadTable()
{
    // Load your Table...
    this.table = new DataTable();
    SqlDataAdapter SDA = new SqlDataAdapter();
    SDA.Fill(table);
    setDataSource(table);
}

internal delegate void SetDataSourceDelegate(DataTable table);
private void setDataSource(DataTable table)
{
    // Invoke method if required:
    if (this.InvokeRequired)
    {
        this.Invoke(new SetDataSourceDelegate(setDataSource), table);
    }
    else
    {
        progressTimer.Enabled = false;
        dataGridView.DataSource = table;
        progressBar.Visible = false;
    }
}

private void progressTimer_Tick(object sender, EventArgs e)
{
    if (this.table != null)
        progressBar.Value = this.table.Rows.Count;
}

これを実行すると、ロード中もアプリケーションの応答性が維持され、ロードされた行数を反映するようにProgressBarが変化します。最後に(DataGridViewでDataSourceを設定したとき)のみ、アプリケーションが「ハング」しているように見えますが、それを回避する方法はないと思います。この操作はメインスレッドからしか実行できないため、UIが応答しなくなることは避けられません。しかし、私のテストでは、DataGridViewは約300万行以上を1秒で簡単に処理できるため、それほど問題にはなりません。

2
Jos Bosmans

問題は、すべてのデータが一緒にロードされ、データベースから戻ることです。データの読み込みの進行状況を取得する必要があります。これはデータベースから実行できます。

  1. データベースからデータ行の数を取得します。 (このクエリは単一の数値を返すため、より高速になります)。

  2. データを分割して取得し(分割統治戦略)、OFFSETおよびFETCHデータベースクエリを使用できます。 (これは、各呼び出しでのデータの戻り部分です)OFFSETおよびFETCHは、異なるデータベースで使用できます。 MSSQLでは、バージョン2012で導入されました。

サーバーから部分的にデータを取得しているときに、進行状況を計算できます。

2
Haseeb Mukhtar