我使用增量加载来显示ListView项。我在后台线程中运行LoadDetails方法,使用Task.Run(...)不占用UI线程。
但是它仍然阻塞UI线程,并且它在完成任务之前不会呈现UI元素。
执行LoadDetails方法大约需要3秒才能完成。
private async void LoadItemCounts(ListViewBase sender, ContainerContentChangingEventArgs args)
{
if (args.Phase != 6)
{
throw new Exception("Not in phase 6");
}
var item = args.Item as ItemModel;
var templateRoot = (Grid)args.ItemContainer.ContentTemplateRoot;
var textBlock = (TextBlock)templateRoot.FindName("textBlock");
await Task.Run(() => LoadDetails(textBlock, item.Id));
}
private async Task LoadDetails(TextBlock textBlock, string id)
{
int count = await DataSource.GetItemCounts(id);
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
textBlock.Text = count.ToString();
});
}如何解决这个问题,使它不会阻塞UI线程?谢谢。
(这是一个Windows运行时应用程序)
发布于 2014-12-01 20:20:18
从你的问题中还不清楚你是如何测量3秒延迟的。对GetItemCounts()的调用本身需要3秒吗?如果是这样的话,这不是意料之中的事吗?延迟是您首先异步执行的原因,不是吗?
你发布的代码看起来不太正确。因为您的新Task不await对LoadDetails()的调用,所以该任务将立即完成,而不会与实际工作同步。从不同的角度来看,您也可以避免直接通过Dispatcher调用。
我会写得更像这样的:
private async void LoadItemCounts(ListViewBase sender, ContainerContentChangingEventArgs args)
{
if (args.Phase != 6)
{
throw new Exception("Not in phase 6");
}
var item = args.Item as ItemModel;
var templateRoot = (Grid)args.ItemContainer.ContentTemplateRoot;
var textBlock = (TextBlock)templateRoot.FindName("textBlock");
await LoadDetails(textBlock, item.Id);
}
private async Task LoadDetails(TextBlock textBlock, string id)
{
int count = await DataSource.GetItemCounts(id);
textBlock.Text = count.ToString();
}也就是说,只要您一直等待UI线程,就不需要通过Dispatcher调用。请注意,以上假设您需要LoadDetails()方法,大概是因为您从多个地方调用它,而有些地方由于某种原因需要这个特定的实现。但是请注意,您可以只编写这样的LoadItemCounts()方法,而忽略了LoadDetails()方法:
private async void LoadItemCounts(ListViewBase sender, ContainerContentChangingEventArgs args)
{
if (args.Phase != 6)
{
throw new Exception("Not in phase 6");
}
var item = args.Item as ItemModel;
var templateRoot = (Grid)args.ItemContainer.ContentTemplateRoot;
var textBlock = (TextBlock)templateRoot.FindName("textBlock");
textBlock.Text = (await DataSource.GetItemCounts(id)).ToString();
}发布于 2014-12-01 15:08:36
您的代码似乎正确地没有使用await阻止UI线程,但是由于LoadItemDetails()大概是在UI线程上被调用的,所以在方法完成其工作之前,它不会完成。
要解决这个问题,只需在调用await时忽略Task.Run(),所以类似于
Task.Run(() => LoadDetails(textBlock, item.Id));应使LoadItemDetails()立即返回。
https://stackoverflow.com/questions/27228580
复制相似问题