我有一个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<bool>...
)
我意识到我在这里缺少一些基本知识-但我认为从异步方法调用Task将允许UI更新吗?既然显然不能在第一种方法后重构它以使页面绑定更新?
我尝试了Task.Run(() => PopulateBinders());
,但没关系。
答案 0 :(得分:0)
在页面已加载后运行异步任务,而不是在OnNavigatedToAsync()
中运行,因为您无意间“阻止”了应用程序运行base.OnNavigatedToAsync()
几秒钟,直到Task.WhenAll
完成运行。
可以通过实现Microsoft.Xaml.Interactivity
将Page.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;
});
}
}
答案 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;
}