[英]Returning from a task without blocking UI thread
我有一个返回数据表的方法。 我需要所有 sql 的东西在一个线程中运行,然后能够在不阻塞 UI 线程的情况下传回数据表。 根据我的理解,当您调用 Task.Result 时,它会阻塞 UI 线程,直到任务完成。 我将如何解决这个问题。 我读过关于使用 await 和 async 的信息,但我还没有完全弄清楚如何在任务中使用它。
public static DataTable LaunchLocationMasterListReport(ObservableCollection<string> BuiltConditionsList, ObservableCollection<string> BuiltSortList, ObservableCollection<ListBoxCheckBoxItemModel> 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<DataTable> LaunchReport(string reportQuery, ObservableCollection<ListBoxCheckBoxItemModel> ColumnsForReport)
{
SqlConnection myConn = new SqlConnection(Settings.Default.UltrapartnerDBConnectionString);
DataTable dt = new DataTable();
string rq = reportQuery;
Task<DataTable> 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>,编译器也会将其转换为 T 的隐式返回类型。
问题是所有异步方法都必须返回 void、Task 或 Task<T>。 所以一旦你开始使用它们,你必须“冒泡”“async”方法属性,直到你可以阻塞结果或者你的方法可以是 void 或 Task(即你已经消耗了实际的结果)。
请参阅这个基于 UI 的简单示例:
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
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<string> _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”应该没问题(并且需要在事件处理程序委托中使用); 无论如何,您的代码并没有调用它。 但从技术上讲,使用“任务”更正确,因此如果在您的上下文中有效,您应该这样做。
没有一个简洁但完整的例子,很难提供比这更具体的东西。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.