2017-02-14 61 views
3

我正在編寫一個WPF應用程序的團隊。我們必須這樣做,以便當用戶隱藏/顯示不同的列時,它將反映在其中一個視圖的ReportViewer控件中。在測試中,我們發現將數據添加到ReportViewer的數據源需要很長時間;有時大約幾秒到可能一分鐘。太長時間我想爲用戶。所以我試圖使用C#的異步並等待。但是,當我申請等待進程管理線然後編譯它時,我從C#編譯器中得到一個錯誤,「無法等待'void'」。在這種情況下,我無法改變.NET框架返回的結果,它是無效的。那麼我該如何處理這種情況呢?下面的代碼:獲取一個無法等待無效,在我想要等待的方法上

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

如果您認爲等待需要很長時間的事情是解決您的問題的方法,那麼您必須對「await」的做法產生誤解。你能描述一下你的信念是關於「等待」嗎?只有等待已經*異步的東西纔有意義;你相信等待*使*不是異步操作的異步操作?它不是。 –

+0

我的理解是,使用async/await可以將控制返回到UI線程,而不是掛起它,等待一些長時間的工作過程完成。但是謝謝你的提問。 – Rod

+0

我的觀點是,如果函數無效返回*和*已經異步然後*它不應該花費太多時間*。如果它無效返回,同步和高延遲,那麼沒有什麼可以「等待」。等待管理現有的異步操作。如果你有一個你想要異步的高延遲操作,'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; await Task.Run(()=> dtTmp = CoreUtils.ToDataTable(itemsSource)); rptViewer.LocalReport.DataSources.Add(new ReportDataSource(「MyData」,dtTmp)); 我不知道在UI組件上使用await會導致異常。謝謝你的頭!上面的內容很快將控件返回到UI線程。再次感謝.. – Rod

4

我幾乎可以確定整條線不是慢速線,它更有可能是CoreUtils.ToDataTable(itemsSource)慢的部分,這是需要改進的部分。

您沒有包括ToDataTable的來源,所以我不能確定最好的方法是什麼,第一個也是最好的選項是編寫一個新版本的函數,該函數在內部利用異步調用來創建函數讓你等待它。

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

第二,較少的高性能的選項是做使用Task.Run然後再打開UI線程設置數據源根據需要在後臺線程的慢的部分。

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