2017-02-14 81 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));