2011-02-08 11 views
3

SQLサーバーから大量のデータをロードするフォームがあります。WinAppフォームがLoadイベント中に大量のデータをロードしています

private void BranchCenter_Load(object sender, EventArgs e) { 
    //Combo boxes: 
    LoadCities(); 
    LoadCoordinators(); 
    LoadComputerSystems(); 

    //Actual entity 
    LoadBranch(); 
} 

private void LoadCities() { 
    //LINQ2SQL to load data. ~5000 records. 
} 

private void LoadCoordinators() { 
    //LINQ2SQL to load data. ~50 records. 
} 

private void LoadComputerSystems() { 
    //LINQ2SQL to load data. ~550 records. 
} 

private void LoadBranch() { 
    LoadBranchInit(); 
    LoadBranchDetails(); 
    LoadBranchTimings(); 
    LoadBranchServices(); 
    LoadBranchLocumsHistory(); 
    LoadBranchJobs(); 
    LoadBranchNotes(); 
} 

private void LoadBranchInit() { 
    //LINQ2SQL to load the Branch object based upon the Branch ID 
} 

private void LoadBranchDetails() { 
    //LINQ2SQL to load basic branch stuff. 38 fields. Mixed editors. 
} 

private void LoadBranchTimings() { 
    //LINQ2SQL to load timings info into 80 date-time controls 
} 

private void LoadBranchServices() { 
    //LINQ2SQL to load services offered at branch info into 20 check-boxes controls 
} 

private void LoadBranchLocumsHistory() { 
    //LINQ2SQL to load branch history info into grid control. Always increasing # of rows :(
} 

private void LoadBranchJobs() { 
    //LINQ2SQL to load branch jobs info into grid control. Always increasing # of rows :( 
} 

private void LoadBranchNotes() { 
    //LINQ2SQL to load branch notes info into grid control 
} 

UIはタブコントロール付きのフォームです。上の各ディテールはタブページに移動します。できるだけ早くフォームをロードしてユーザーに表示する必要があります。フォームが表示されたら、各ページのデータを取得するために一連のバックグラウンドワーカーを起動する必要があります。

私はバックグラウンドワーカーを混乱させようとしていますが、その使い方を理解できません。 「別のスレッドがメインスレッドのコントロールにアクセスしようとしました...またはそのようなもの...」

理想的な状況は、すべてのタブにデータをロードするプログレスバーを持つことです。それぞれのバックグラウンドワーカーが終了すると相互作用可能になる。

どのような戦略やアドバイスですか?読んでいただきありがとうございます。

答えて

1

各タブのBackgroundWorkerを作成します。フォームのLoadイベントで、すべてのタブを無効にし、各バックグラウンドワーカーのRunWorkerAsync()メソッドを呼び出します。

各DoWorkイベントハンドラで、関連するタブページに必要なデータをデータベースからデータテーブルにロードし、DoWorkEventArgsのResultプロパティをデータテーブルに設定します。

注:DoWorkイベントハンドラでは、別のスレッドで動作しているので、UIコントロールを更新しないでください。データベースからデータを取得し、Resultプロパティを設定するだけです。

RunWorkerCompletedイベントハンドラでは、RunWorkerCompletedEventArgsのResultプロパティを取得することによって、DoWorkイベントハンドラで取得したデータテーブルにアクセスできます。それに応じてUIコントロールのプロパティを設定し、現在のバックグラウンドワーカーに関連付けられたタブページを有効にすることができます。

3

各タイプのデータが1ページに表示される場合は、各タブページが初めてロードされるときに、対応するタイプのデータが読み込まれるようにコードを移動します。こうすることで、データの読み込み作業がより長時間に渡って分散され、ユーザーがセッション中にすべてのタブに移動しなければ、おそらく避けられます。

ページをロードするときには、BackgroundWorkerまたはその他の非同期メカニズムを使用できます。タブページでは、2つのパネルコントロールを使用できます。フォームの読み込み時にVisible = falseを持つページと、「読み込んでいます。お待ちください...」のようなテキストが含まれています。ページのデータがロードされ、UIが更新されると、2つのパネルの表示を切り替えてUIを表示します。そうすれば、データがロードされている間もフォームは応答し、一度に1ページだけデータをロードするので、ロード時間はかなり短くなければなりません。

1

ここでの問題は、BackgroundWorkerのDoWorkメソッドがGUIに触れることができないことです。

GUIを自由に更新できるGUIスレッド上でメソッドを呼び出すには、BackgroundWorker.ReportProgress(int progress, object state)を使用する必要があります。

ここで重要な点は、GUIコントロールはGUIスレッド自体からのみ更新する必要があります。そうしないと、プログラム内の任意の例外がランダムに発生します。

3

理想的な解決策は、フォームのロードイベントでデータを実際にロードしないことです。

UIのレンダリングが完全に完了するように、フォームが正しくロードされるようにします。

その後、必要に応じてプログレスバーを表示して、同期または非同期のいずれかの実際のデータ読み込みを実行できます。

同時に読み込まれたものすべてを必要としない場合は、タブが初めてアクセスされたときにのみデータを読み込むことも考えられます。たとえば、ユーザーが最後のタブをクリックしないと、それのための何か。

1

UIスレッドとは別のスレッドからUIを混乱させることはできません。それがあなたのエラーの原因です。別のスレッドからUI要素を正しく更新する方法の詳細については、Invokeを使用する必要があります。 This Stack Overflowに関する質問があなたを助けてくれるかもしれません。

0

バックグラウンドワーカースレッドで発生している問題だけに対処するには、スレッド自体からUIコンポーネントにアクセスしようとしているように思えます。これを非UIスレッドから行うには、コンポーネントに直接アクセスするのではなく、Control.Invokeを使用する必要があります。

1

はい、BackgroundWorkerはこれに最適です。

DoWorkイベントでフォームを変更したいので間違っていると思います。

しかし、あなただけのその後RunWorkerCompletedにフォームを変更するには、そのe.Resultsを使用して、そのイベント

のe.Resultsにこの結果を収集する必要があります。

+0

データは、e.Resultでうまく動作するにはあまりにも多くすぎます...しかし、私は実際に一度戻ってくることができます。 – DoomerDGR8

+0

なぜそれはあまりにもですか?非同期に取得する場合は、GUI以外のスレッドで変数を収集し、UIスレッドを呼び出してUIでデータを更新する必要があります。 BackgroundWorkerは実際にこれを行います。スレッドを使用すると柔軟になることができますが、おそらく問題にはならないでしょう。だから、実際の大規模なデータセットでBackgroundWorkerを試したことが分かりませんが、コンピュータのメモリ容量が大きすぎないと悪いことは起こりません。 –

0

大丈夫です。まもなく大量の応答があります。この場所を愛する。リンク2リンクからジャンプすると、私はReactive Extensions for .NET (Rx)と対面しました。これは良い代替物でもありますか?自分のシナリオでRxを使用する方法に関するチュートリアルを見つけることができません。

1

TabControlはすでにレイジーロードしています。

自分で好きにして、各タブの内容をUserControlに配置します。

+0

"_TabControl_は既にレイジーロードしています。" ..私の頭の中からこの歌を得ることはできません。したがって、フォームのロード時に、私は 'LoadBranchInit();'私は残りのメソッドを 'LoadBranch *();'と呼びます。タブページごとのinit? – DoomerDGR8

+0

多かれ少なかれ。 Tabを最初に表示するタイミングを決定するロジックが必要です。 UCを使用すると、OnLoadイベントを使用できます。 –

+0

たとえば、http://stackoverflow.com/q/3670694/60761 –

0

さて、私は新しいシナリオに直面します。私はVisual Studio 2010にシフトし、Task.Factory.StartNew(()=> myMethod());

private void LoadLocum() { 
    var TaskInit = Task.Factory.StartNew(() => LoadLocumInit()); 
    TaskInit.Wait(); 

    var TaskDetails = Task.Factory.StartNew(() => LoadLocumDetails()); 
    TaskDetails.Wait(); 

    var TaskQualifications = Task.Factory.StartNew(() => LoadLocumQualifications()); 
    //Enable Qualification TabPage automatically whenever TaskQualifications is complete 

    Parallel.Invoke(
     () => LoadLocumComputerSystems(), 
     () => LoadLocumOtherInfo(), 
     () => LoadLocumEmergencyContacts(), 
     () => LoadLocumDistanceRates(), 
     () => LoadLocumDocuments(), 
     () => LoadLocumNotes(), 
     () => LoadLocumBannedStatus() 
    ); 

} 

最初の2つのステップ(タスク)が不可欠である:

は、これは私がこれまで持っているものです。これで、タブのタブページが無効になりました。私は、関連するタスクの完了に基づいてそれらを有効にする必要があります。特定のタスクが完了したかどうかを示すイベントを見つけることができます。

+0

を参照してください。また、ParalleledまたはTaskedされているメソッドを介して任意のUIにアクセスすることはまだOKではありません。それで、私は後でTaskedメソッドのUIコントロールにアンパックすることができますか? – DoomerDGR8

関連する問題