UWP页面在Windows 10 Mobile上崩溃但桌面端运行正常的问题求助
嘿,我仔细看了你的代码和问题描述,先给你捋几个大概率导致Windows 10 Mobile崩溃的坑,毕竟Mobile和桌面的UWP运行环境差异还是挺明显的:
PasswordBox绑定的致命问题
你在XAML里直接给PasswordBox.Password做了双向绑定,但这里要敲黑板:UWP的PasswordBox的Password属性天生不支持数据绑定!桌面端可能因为调试环境或者兼容性宽松没触发崩溃,但Mobile上这个绑定失败会直接导致页面初始化出错进而崩溃,这个是最可能的元凶。
解决办法是用自定义附加属性绕开这个限制,比如写个小工具类:public static class PasswordBoxHelper { public static readonly DependencyProperty BoundPasswordProperty = DependencyProperty.RegisterAttached("BoundPassword", typeof(string), typeof(PasswordBoxHelper), new PropertyMetadata(string.Empty, OnBoundPasswordChanged)); public static string GetBoundPassword(DependencyObject d) => (string)d.GetValue(BoundPasswordProperty); public static void SetBoundPassword(DependencyObject d, string value) => d.SetValue(BoundPasswordProperty, value); private static void OnBoundPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is PasswordBox pb) { pb.PasswordChanged -= OnPasswordChanged; if (!string.Equals(pb.Password, e.NewValue as string)) { pb.Password = e.NewValue as string; } pb.PasswordChanged += OnPasswordChanged; } } private static void OnPasswordChanged(object sender, RoutedEventArgs e) { if (sender is PasswordBox pb) { SetBoundPassword(pb, pb.Password); } } }然后XAML里改成这样用:
<PasswordBox local:PasswordBoxHelper.BoundPassword="{Binding Account.Password, Mode=TwoWay}" />同步数据库操作阻塞UI线程
你的ViewModel里AccountTypes、SyncTypes的getter还有Load方法都是同步访问数据库的,Windows 10 Mobile的性能远不如桌面,UI线程的超时限制更严格,同步IO很容易导致线程阻塞,触发系统的崩溃机制。
建议改成异步加载:- 先给ViewModel加私有字段缓存数据,异步初始化:
private AccountType[] _accountTypes; public AccountType[] AccountTypes { get => _accountTypes; private set => SetProperty(ref _accountTypes, value); } private SyncType[] _syncTypes; public SyncType[] SyncTypes { get => _syncTypes; private set => SetProperty(ref _syncTypes, value); } private async Task LoadLookupDataAsync() { using (var dbContext = new DavConnectorDbContext()) { AccountTypes = await dbContext.AccountTypes.AsNoTracking().ToArrayAsync(); SyncTypes = await dbContext.SyncTypes.AsNoTracking().ToArrayAsync(); } } - 把
Load改成异步方法:public async Task LoadAsync(Guid? id) { if (id.HasValue) { using (var dbContext = new DavConnectorDbContext()) { Account = await dbContext.Accounts.AsNoTracking().SingleOrDefaultAsync(acc => acc.Id == id); } } Account ??= new Account { Id = Guid.NewGuid() }; } - 页面的
OnNavigatedTo里异步调用:protected override async void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); var vm = DataContext as EditAccountPageViewModel; vm.AccountEditCompleted += EditAccountPage_AccountEditCompleted; // 先加载下拉选项数据 await vm.LoadLookupDataAsync(); // 加载账户数据 if (e.Parameter is Guid accountId) { await vm.LoadAsync(accountId); } else { await vm.LoadAsync(null); } }
- 先给ViewModel加私有字段缓存数据,异步初始化:
最低SDK版本的兼容性问题
你设置的最低SDK是10.0.10240.0,这个版本的Windows 10 Mobile是初代版本,有一堆API兼容性问题,比如EF Core(如果用的是它的话)在这个版本上的支持就很有限。建议尝试把最低SDK版本提到10.0.14393.0(周年更新),这个版本的Mobile系统稳定性和API覆盖都好很多,而且现在还在使用的Windows 10 Mobile设备基本都是这个版本及以上。最后建议抓崩溃日志
你可以用Visual Studio连接Mobile设备调试,打开输出窗口看详细的异常信息,或者在App.xaml.cs里加全局异常捕获:public App() { this.InitializeComponent(); this.Suspending += OnSuspending; this.UnhandledException += App_UnhandledException; } private void App_UnhandledException(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e) { Debug.WriteLine($"崩溃原因: {e.Message}\n堆栈跟踪: {e.Exception.StackTrace}"); e.Handled = true; // 调试时标记为已处理,方便看详细信息 }这样能精准定位到崩溃的具体代码行,比瞎猜靠谱多了。
先试试解决PasswordBox绑定和同步数据库这两个问题,应该能解决大部分情况。
内容来源于stack exchange

