2017-02-14 13 views
3

私はWPFアプリケーションを書くチームにいます。ユーザーが異なる列を表示/非表示にしたときに、ビューの1つのReportViewerコントロールに反映されるようにする必要があります。テストでは、ReportViewerのデータソースにデータを追加するのに時間がかかることがわかりました。場合によっては数分のオーダーであることもあります。あまりにも私はユーザーのために考える。だから、私はC#の非同期を使用しようとしていると待っている。しかし、私がプロセスホッグである行を待ってコンパイルしたとき、C#コンパイラから「voidを待つことはできません」というエラーが出ます。この場合、私は.NETフレームワークが返すもの、その無効を変更することはできません。だから私はこの状況にどう対処しますか?ここでは、コードがあります:本質的に同期している方法については私は待ち望んでいるメソッドでvoidを待つことができません

private async Task GenerateReportAsync() 
{ 
    DataSet ds = new DataSet(); 
    DataTable dt = new DataTable(); 
    dt.Clear(); 
    int iCols = 0; 
    //Get the column names 
    if (Columns.Count == 0)  //Make sure it isn't populated twice 
    { 
     foreach (DataGridColumn col in dataGrid.Columns) 
     { 
      if (col.Visibility == Visibility.Visible) 
      { 
       Columns.Add(col.Header.ToString());  //Get the column heading 
       iCols++; 
      } 
     } 
    } 
    //Create a DataTable from the rows 
    var itemsSource = dataGrid.ItemsSource as IEnumerable<Grievance>; 
    if (this.rptViewer != null) 
    { 
     rptViewer.Reset(); 
    } 
    rptViewer.LocalReport.DataSources.Clear(); 
    if (m_rdl != null) 
    { 
     m_rdl.Dispose(); 
    } 
    Columns = GetFieldOrder(); 
    m_rdl = CoreUtils.GenerateRdl(Columns, Columns); 
    rptViewer.LocalReport.LoadReportDefinition(m_rdl); 
    //the next line is what takes a long time 
    await rptViewer.LocalReport.DataSources.Add(new ReportDataSource("MyData", CoreUtils.ToDataTable(itemsSource))); 
    rptViewer.RefreshReport(); 
} 
+6

長い時間を要するものを待っていることが問題の解決策だと思うなら、「待っている」ことについて何らかの誤った信念が必要です。あなたの信念が「待っている」ことについて何か説明できますか?すでに非同期のものを待つだけで意味があります。非同期操作ではないものを待っていると思いますか?それはしません。 –

+0

async/awaitを使用すると、UIスレッドに制御を戻すことが可能になり、長い作業プロセスが完了するのを待って、ハングアップすることは理解できます。しかし、頼んでくれてありがとう。 – Rod

+0

私の主張は、関数がvoidで*と*がすでに非同期の場合は、*それは時間がかかりません*。戻り値が無効で、同期しており、待ち時間が長い場合は、「待つ」ことはありません。 Awaitは、既存の非同期操作を管理します。待機時間の長い操作を非同期にしたい場合、 'await'はあなたを助けません。他のメカニズムを使って非同期にする方法を理解しなければなりません。 –

答えて

6

、あなたはそれを待つことができますので、あなた自身のTaskでそれらをラップする必要があります。あなたのケースでは、私はちょうどTask.Runを使用します。

await Task.Run(() => 
{ 
    rptViewer.LocalReport.DataSources.Add(new ReportDataSource("MyData", CoreUtils.ToDataTable(itemsSource))); 
}); 

は、タスクを生成する方法は他にもありますが、これはおそらく最も簡単です。これによりUIコンポーネントが更新された場合、これらの操作はUIスレッドで行われる必要があるため、例外がスローされる可能性があります。この場合、UI関連の部分を長時間実行している部分から離して取得し、長い部分のみをTaskにラップしてみてください。

+3

バックグラウンドスレッドからレポートビューアのようなUIコンポーネントにアクセスしているため、クロススレッド例外が発生する可能性があります。 –

+0

@ScottChamberlain絶対に、私はこれに注意しました。 – BradleyDotNET

+0

@BradleyDotNET私はあなたの提案をして、以下を考え出しました: DataTable dtTmp = null; を待ちます。Task.Run(()=> dtTmp = CoreUtils.ToDataTable(itemsSource)); rptViewer.LocalReport.DataSources.Add(新しいReportDataSource( "MyData"、dtTmp)); UIコンポーネントの待機を使用すると例外が発生することはわかりませんでした。ヘッドアップをありがとう!上記のようにすれば、UIスレッドに制御を迅速に戻すことができます。ありがとう、もう一度.. – Rod

4

私は、ライン全体が遅いラインではないことがほとんどわかります。CoreUtils.ToDataTable(itemsSource)は遅いピースであり、改善が必要な部分です。

ToDataTableのソースが含まれていないので、最善の方法は何かを言うことはできません。最初に最適なオプションは、内部的に非同期呼び出しを利用して関数を作成する新しいバージョンの関数を作成することですそれはあなたがそれを待つことを可能にする。

var data = await CoreUtils.ToDataTableAsync(itemsSource) 
rptViewer.LocalReport.DataSources.Add(new ReportDataSource("MyData", data)); 

秒、より少ないパフォーマンスのオプションは、必要に応じてバックUIスレッド上で次にTask.Runを使用してバックグラウンドスレッドで遅い部分を行うデータソースに設定されています。

var data = await Task.Run(() => CoreUtils.ToDataTable(itemsSource)); 
rptViewer.LocalReport.DataSources.Add(new ReportDataSource("MyData", data)); 
関連する問題