web-dev-qa-db-ja.com

私が待ちたいメソッドで、cannot awaitvoidを取得する

私はWPFアプリを作成しているチームに所属しています。ユーザーがさまざまな列を非表示/表示したときに、ビューの1つにあるReportViewerコントロールにそれが反映されるようにする必要があります。テストの結果、ReportViewerのデータソースにデータを追加するのに長い時間がかかることがわかりました。時には数秒からおそらく1分程度です。ユーザーにとっては長すぎると思います。だから私はC#の非同期を使用して待っています。ただし、プロセスホッグである行にawaitを適用してコンパイルすると、C#コンパイラから「Cannotawait'void '」というエラーが表示されます。この場合、.NETFrameworkが返すものを変更することはできません。では、どうすればこの状況に対処できますか?コードは次のとおりです。

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();
}
5
Rod

本質的に同期しているメソッドの場合は、それを待つことができるように、独自のTaskでラップする必要があります。あなたの場合、私はTask.Runを使用します:

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

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

9
BradleyDotNET

線全体が遅い線ではないことはほぼ確実です。CoreUtils.ToDataTable(itemsSource)が遅い部分である可能性がはるかに高く、それが改善が必要な部分です。

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

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

2番目のパフォーマンスの低いオプションは、Task.Runを使用してバックグラウンドスレッドで遅い部分を実行し、UIスレッドに戻って必要に応じてデータソースを設定することです。

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