如何在Windows运行时中的后台线程上运行代码

时间:2014-12-01 12:36:23

标签: c# xaml windows-runtime windows-phone winrt-xaml

我使用增量加载来显示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 Phone运行时应用)

2 个答案:

答案 0 :(得分:2)

从您的问题中不清楚您是如何测量3秒延迟的。调用GetItemCounts()本身需要3秒钟吗?如果是这样,那不是预期的吗?延迟是你首先异步执行的原因,不是吗?

您发布的代码看起来并不十分正确。由于您的新Task没有awaitLoadDetails()的调用,该任务将立即完成,而不会与正在进行的实际工作同步。换句话说,您也可以避免直接通过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();
}

答案 1 :(得分:1)

看起来您的代码使用await正确地阻止了UI线程,但由于可能在UI线程上调用LoadItemDetails(),因此在方法完成其工作之前它不会完成。 / p>

要解决此问题,请在调用await时忽略Task.Run(),这样就像

Task.Run(() => LoadDetails(textBlock, item.Id));

应立即让LoadItemDetails()返回。