从任务返回而不阻止UI线程

我有一个返回数据表的方法。 我需要在线程中运行所有sql东西,然后能够传回一个数据表,而不会阻塞UI线程。 根据我的理解,当您调用Task.Result时,它会阻止UI线程,直到任务完成。 我该如何解决这个问题。 我读到了关于使用await和async的问题,但我还没有弄清楚如何在任务中使用它。

public static DataTable LaunchLocationMasterListReport(ObservableCollection BuiltConditionsList, ObservableCollection BuiltSortList, ObservableCollection ColumnsForReport, bool LocationNotesCheckBox, ref string reportQuery, ref string reportQueryforSave, ref string reportView, ref string queryCondtions) { queryCondtions = BuildConditionAndSorts(queryCondtions, BuiltConditionsList, BuiltSortList); reportQueryforSave = "SELECT * FROM LocationMasterReportView"; reportView = "LocationMasterReportView"; reportQuery = "SELECT * FROM LocationMasterReportView " + queryCondtions; return LaunchReport(reportQuery, ColumnsForReport).Result; } async private static Task LaunchReport(string reportQuery, ObservableCollection ColumnsForReport) { SqlConnection myConn = new SqlConnection(Settings.Default.UltrapartnerDBConnectionString); DataTable dt = new DataTable(); string rq = reportQuery; Task task = Task.Factory.StartNew(() => { using (SqlCommand comm = new SqlCommand(rq, myConn)) { myConn.Open(); dt.Load(comm.ExecuteReader()); myConn.Close(); } if (dt.Rows.Count == 0) { MessageBox.Show("Contains No Results"); return null; } foreach (ListBoxCheckBoxItemModel lbc in ColumnsForReport) { if (!lbc.IsSelected) { dt.Columns.Remove(lbc.Name.ToString()); } } return dt; }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); return await task; } 

我同意使用async / await是最好的方法。 如上所述,当您等待异步方法时,即使声明的返回类型是Task ,编译器也会将其转换为T的隐式返回类型。

问题是所有异步方法都必须返回void,Task或Task 。 因此,一旦你开始使用它们,你必须“冒泡”“异步”方法属性,直到你可以阻止结果或你的方法可能是无效或任务(即你已经消耗了实际)结果)。

请参阅这个简单的基于UI的示例:

 ///  /// Interaction logic for MainWindow.xaml ///  public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private async void Button_Click(object sender, RoutedEventArgs e) { statusText.Text = "Running"; statusText.Text = await _ComputeText(true); statusText.Text = await _ComputeText(false); } private static async Task _ComputeText(bool initialTask) { string result = await Task.Run(() => { Thread.Sleep(2000); return initialTask ? "Task is done!" : "Idle"; }); return result; } } 

请注意,按钮事件处理程序“Button_Click”只是声明为“void”返回。 但我可以这样做,因为我在该方法中使用异步结果。

在您的情况下,在异步任务完成之前,返回的DataTable不可用。 因此,您必须将每个方法声明为“异步”,一直回到实际使用DataTable执行某些操作的方法。 即使在那里,该方法也需要声明为异步,但您不会返回DataTable,因此该方法可以返回类型为“void”或“Task”。 一个常见的场景是这个方法是一个UI事件处理程序,所以“void”应该没问题(并且需要在事件处理程序委托中使用); 你的代码还没有调用它。 但是在技术上更恰当地使用“任务”,所以如果在你的上下文中有效,你应该这样做。

如果没有一个简洁但完整的例子,很难提供比这更具体的东西。