如何实现带异步加载与取消功能的NavigationView页面导航?
核心逻辑
- 维护全局的取消令牌源(
CancellationTokenSource),每次触发新导航时先终止旧的加载任务 - 将页面加载逻辑封装为异步方法,用
await避免阻塞UI线程 - 加载过程中给导航项添加状态反馈,提升用户感知
具体实现步骤
1. 定义全局变量
在主窗口类中声明用于跟踪当前导航任务的变量:
private CancellationTokenSource _currentNavigationCts;
2. 处理导航项点击事件
异步处理NavigationView.ItemInvoked事件,在新导航触发时取消旧任务:
private async void NavigationView_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args) { // 终止当前正在进行的加载任务 _currentNavigationCts?.Cancel(); _currentNavigationCts?.Dispose(); // 创建新的取消令牌源 _currentNavigationCts = new CancellationTokenSource(); var cancellationToken = _currentNavigationCts.Token; var invokedItem = args.InvokedItemContainer as NavigationViewItem; if (invokedItem == null) return; // 标记导航项为加载中(可选) invokedItem.IsEnabled = false; var originalIcon = invokedItem.Icon; invokedItem.Icon = new SymbolIcon(Symbol.Sync); try { // 异步加载目标页面 var targetPage = await LoadTargetPageAsync(invokedItem.Tag.ToString(), cancellationToken); // 确认任务未被取消后,执行页面导航 if (!cancellationToken.IsCancellationRequested) { ContentFrame.Navigate(targetPage.GetType()); } } catch (OperationCanceledException) { // 任务被取消,无需额外处理 } finally { // 恢复导航项状态 invokedItem.IsEnabled = true; invokedItem.Icon = originalIcon; } }
3. 异步页面加载方法
封装页面初始化逻辑,支持取消令牌终止任务:
private async Task<Page> LoadTargetPageAsync(string pageIdentifier, CancellationToken cancellationToken) { // 模拟耗时操作:比如加载远程数据、初始化复杂控件 await Task.Delay(1500, cancellationToken); // 根据标识创建对应页面实例 return pageIdentifier switch { "Home" => new HomePage(), "Settings" => new SettingsPage(), "Dashboard" => new DashboardPage(), _ => new HomePage() }; }
关键注意事项
- 页面内部的耗时初始化逻辑(如数据加载)也需传入取消令牌,确保能被及时终止
- 避免在页面构造函数中执行异步操作,可将异步初始化逻辑放在页面的
Loaded事件中,并传入取消令牌 - 可给内容框架(ContentFrame)添加加载动画,进一步优化加载过程的用户体验
内容的提问来源于stack exchange,提问作者Signalist
相关产品推荐
相关产品推荐

