如何保持UWP UI的响应速度?

时间:2018-12-02 01:59:01

标签: c# mvvm uwp async-await template10

我有一个UWP应用,其中一个页面需要执行三个任务-第一个是加载页面的主要内容(从我们的API中检索的“活页夹”对象的集合),然后加载其他内容不以任何方式依赖于第一任务的内容。

我的页面支持ViewModel(我使用的是默认的Template10 MVVM模型),当页面导航到后,我可以通过VM OnNavigatedToAsync方法执行此操作:

public async override Task OnNavigatedToAsync(object parameter, NavigationMode mode, IDictionary<string, object> state)
{
    if (mode == NavigationMode.New || mode == NavigationMode.Refresh)
    {
        IsBusy = true;      //Show progress ring
        CreateServices();   //Create API service

        //Download binders for board and populate ObservableCollection<Binder>
        //This has a cover image and other info I want to show in the UI immediately 
        await PopulateBinders();

        //Get files and calendar events for board
        //Here I want to run this on a different thread so it does 
        //not stop UI from updating when PopulateBinders() is finished
        await Task.WhenAll(new[]
        {
            PopulateBoardFiles(),
            PopulateBoardEvents()
        });               

        IsBusy = false;
        await base.OnNavigatedToAsync(parameter, mode, state);
        return;          
    }
}

因此主要任务是PopulateBinders()-这将调用API,返回数据并将其加载到Binder的ObservableCollection中。运行此命令后,我希望UI更新其绑定并立即显示Binder对象,但它会等到WhenAll任务中的其他两个任务都运行完之后再更新UI。 (所有这三个任务都定义为private async Task&lt;bool&gt;...

我意识到我在这里缺少一些基本知识-但我认为从异步方法调用Task将允许UI更新吗?既然显然不能在第一种方法后重构它以使页面绑定更新?

我尝试了Task.Run(() => PopulateBinders());,但没关系。

2 个答案:

答案 0 :(得分:0)

在页面已加载后运行异步任务,而不是在OnNavigatedToAsync()中运行,因为您无意间“阻止”了应用程序运行base.OnNavigatedToAsync()几秒钟,直到Task.WhenAll完成运行。

可以通过实现Microsoft.Xaml.InteractivityPage.Loaded事件与视图模型中的DelegateCommand类绑定来实现MVVM中的已加载事件。

XAML页面(假设您使用Prism作为MVVM框架)

<Page ...
    xmlns:core="using:Microsoft.Xaml.Interactions.Core"
    xmlns:interactivity="using:Microsoft.Xaml.Interactivity">
    <interactivity:Interaction.Behaviors>
        <core:EventTriggerBehavior EventName="Loaded">
            <core:InvokeCommandAction Command="{x:Bind Path=Vm.PageLoaded}" />
        </core:EventTriggerBehavior>
    </interactivity:Interaction.Behaviors>
</Page>

在您的视图模型中:

public class PageViewModel : ... //some interface or else 
{
    public DelegateCommand PageLoaded;
    public PageViewModel(...)
    {
         PageLoaded = new DelegateCommand(async () =>
         {
                IsBusy = true;      
                CreateServices();  

                await PopulateBinders();

                await Task.WhenAll(new[]
                {
                    PopulateBoardFiles(),
                    PopulateBoardEvents()
                });               

                IsBusy = false;
         });
    }
}

了解更多:Binding UWP Page Loading/ Loaded to command with MVVM

答案 1 :(得分:-1)

我希望这段代码可以帮助您按预期更新用户界面:

public async override Task OnNavigatedToAsync(object parameter, NavigationMode mode, IDictionary<string, object> state)
{
    if (mode == NavigationMode.New || mode == NavigationMode.Refresh)
    {
        IsBusy = true;      //Show progress ring
        CreateServices();   //Create API service

        //Download binders for board and populate ObservableCollection<Binder>
        //This has a cover image and other info I want to show in the UI immediately 
        await PopulateBinders();

        await PouplateBoardData();

        await base.OnNavigatedToAsync(parameter, mode, state);
        return;          
    }
}

private async void PopulateBoardData()
{
    await Task.WhenAll(new[]
    {
            PopulateBoardFiles(),
            PopulateBoardEvents()
    });               

    IsBusy = false;
}