Как сохранить UWP UI отзывчивым? - PullRequest
0 голосов
/ 02 декабря 2018

У меня есть приложение UWP, в котором одна из страниц должна выполнить три задачи - первая - это загрузить основной контент для страницы (набор объектов 'Binders', полученный из нашего 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, возвращает данные и загружает их в ObservableCollection of Binder.После этого я хочу, чтобы пользовательский интерфейс обновил свои привязки и немедленно показал объекты Binder, но вместо этого он ждет, пока две другие задачи в WhenAll Task) запустятся, прежде чем обновлять пользовательский интерфейс.(Все эти три задачи определены как private async Task&lt;bool&gt;...)

Я понимаю, что мне здесь не хватает чего-то базового - но я подумал, что вызов Task из асинхронного метода позволит обновить пользовательский интерфейс?Поскольку это явно не позволяет мне сделать рефакторинг для обновления привязок моей страницы после первого метода?

Я пытался Task.Run(() => PopulateBinders());, но это не имело никакого значения.

Ответы [ 2 ]

0 голосов
/ 03 декабря 2018

Вместо запуска внутри OnNavigatedToAsync(), запустите асинхронную задачу, когда страница уже загружена, поскольку вы непреднамеренно «блокируете» приложение для запуска base.OnNavigatedToAsync() в течение нескольких секунд, пока Task.WhenAll не завершит работу.

Выполнение загруженного события в MVVM может быть достигнуто путем реализации Microsoft.Xaml.Interactivity для связывания Page.Loaded события с классом DelegateCommand в вашей модели представления.

Страница 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;
         });
    }
}

Подробнее: Привязка загрузки страницы UWP / Загрузка команды с MVVM

0 голосов
/ 03 декабря 2018

Надеюсь, этот код поможет вам обновить интерфейс, как и ожидалось:

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;
}
...