wpf 在我想要等待的方法上获得不能等待无效
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/42233787/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Getting a Cannot await void, on a method that I have want to await on
提问by Rod
I'm on a team writing a WPF app. We have to make it so that when a user hides/shows different columns that it will reflect that in a ReportViewer control on one of the views. In testing we've found that it takes a long time to add the data to the ReportViewer's data sources; sometimes on the order of several seconds to possibly a minute. Too long I think for the users. So I'm trying to use C#'s async and await. However, when I applied await to the line that is the process hog and then compile it, I get an error from the C# compiler, "Cannot await 'void'". In this case, I cannot change what the .NET framework returns, its void. So how do I handle this situation? Here's the code:
我在一个编写 WPF 应用程序的团队中。我们必须做到这一点,当用户隐藏/显示不同的列时,它将反映在其中一个视图的 ReportViewer 控件中。在测试中我们发现将数据添加到ReportViewer的数据源需要很长时间;有时几秒到一分钟。我为用户考虑的时间太长了。所以我正在尝试使用 C# 的异步和等待。但是,当我将 await 应用于进程猪的行然后编译它时,我从 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();
}
回答by BradleyDotNET
For methods that are inherently synchronous, you need to wrap them in your own Taskso you can await it. In your case, I would just use Task.Run:
对于本质上是同步的方法,您需要将它们包装在您自己的方法中,Task以便您可以等待它。在你的情况下,我只会使用Task.Run:
await Task.Run(() =>
{
rptViewer.LocalReport.DataSources.Add(new ReportDataSource("MyData", CoreUtils.ToDataTable(itemsSource)));
});
There are other ways to generate a task, but this one is probably the easiest. If this updates a UI component, it will likely throw an exception because those operations must occur on the UI thread. In this case, try to get the UI related piece away from the long-running part and only wrap the long part in the Task.
还有其他方法可以生成任务,但这种方法可能是最简单的。如果这更新了 UI 组件,它可能会抛出异常,因为这些操作必须在 UI 线程上发生。在这种情况下,尝试将 UI 相关的部分从长时间运行的部分中取出,只将长部分包裹在Task.
回答by Scott Chamberlain
I can almost be certain that the entire line is not the slow line, it is much more likely that CoreUtils.ToDataTable(itemsSource)is the slow piece and that is the part that needs to be improved.
我几乎可以肯定整条线不是慢线,更有可能CoreUtils.ToDataTable(itemsSource)是慢线,那是需要改进的部分。
You did not include the source of ToDataTableso I can't say for sure what the best way would be, the first and best option would be write a new version of the function that leverages async calls internally to create a function that allows you to await it.
您没有包含的来源,ToDataTable所以我不能确定最好的方法是什么,第一个也是最好的选择是编写一个新版本的函数,该函数在内部利用异步调用来创建一个允许您等待的函数它。
var data = await CoreUtils.ToDataTableAsync(itemsSource)
rptViewer.LocalReport.DataSources.Add(new ReportDataSource("MyData", data));
The second, less performant option is do the slow part on a background thread using Task.Runthen back on the UI thread set the data source as needed.
第二个性能较低的选项是在后台线程上执行慢速部分,Task.Run然后在 UI 线程上根据需要设置数据源。
var data = await Task.Run(() => CoreUtils.ToDataTable(itemsSource));
rptViewer.LocalReport.DataSources.Add(new ReportDataSource("MyData", data));

