翼度科技»论坛 编程开发 .net 查看内容

WPFUI报错 - page does not have a parameterless constructor

7

主题

7

帖子

21

积分

新手上路

Rank: 1

积分
21
WPFUI报错

page does not have a parameterless constructor. If you are using Wpf.Ui.IPageService do not navigate initially and don't use Cache or Precache
问题原因

WPFUI中的NavigationView只支持导航页面的无参构造函数或含一个dataContext的有参构造函数。因为在View的构造函数中注入了一些服务,导致View创建失败,WPFUI报错。
问题处理

查看异常堆栈,找报错位置:
  1. 在 Wpf.Ui.Controls.NavigationViewActivator.CreateInstance(Type pageType, Object dataContext) 在 Wpf.Ui.Controls\NavigationViewActivator.cs 中: 第 37 行
  2. 在 Wpf.Ui.Controls.NavigationView.GetPageInstanceFromCache(Type targetPageType) 在 Wpf.Ui.Controls\NavigationView.cs 中: 第 1206 行
  3. 在 Wpf.Ui.Controls.NavigationCache.Remember(Type entryType, NavigationCacheMode cacheMode, Func`1 generate) 在 Wpf.Ui.Controls\NavigationCache.cs 中: 第 25 行
  4. 在 Wpf.Ui.Controls.NavigationView.GetNavigationItemInstance(INavigationViewItem viewItem) 在 Wpf.Ui.Controls\NavigationView.cs 中: 第 1185 行
  5. 在 Wpf.Ui.Controls.NavigationView.NavigateInternal(INavigationViewItem viewItem, Object dataContext, Boolean addToNavigationStack, Boolean isBackwardsNavigated) 在 Wpf.Ui.Controls\NavigationView.cs 中: 第 1131 行
  6. 在 Wpf.Ui.Controls.NavigationViewItem.OnClick() 在 Wpf.Ui.Controls\NavigationViewItem.cs 中: 第 314 行
  7. ...
复制代码
看源码,找解决方案:
  1. private object GetNavigationItemInstance(INavigationViewItem viewItem)
  2. {
  3.     if (viewItem.TargetPageType is null)
  4.     {
  5.         throw new InvalidOperationException(
  6.             $"The {nameof(viewItem)}.{nameof(viewItem.TargetPageType)} property cannot be null."
  7.         );
  8.     }
  9.     if (_serviceProvider is not null)
  10.     {
  11.         return _serviceProvider.GetService(viewItem.TargetPageType)
  12.             ?? throw new InvalidOperationException(
  13.                 $"{nameof(_serviceProvider)}.{nameof(_serviceProvider.GetService)} returned null for type {viewItem.TargetPageType}."
  14.             );
  15.     }
  16.     if (_pageService is not null)
  17.     {
  18.         return _pageService.GetPage(viewItem.TargetPageType)
  19.             ?? throw new InvalidOperationException(
  20.                 $"{nameof(_pageService)}.{nameof(_pageService.GetPage)} returned null for type {viewItem.TargetPageType}."
  21.             );
  22.     }
  23.     return _cache.Remember(
  24.             viewItem.TargetPageType,
  25.             viewItem.NavigationCacheMode,
  26.             ComputeCachedNavigationInstance
  27.         )
  28.         ?? throw new InvalidOperationException(
  29.             $"Unable to get or create instance of {viewItem.TargetPageType} from cache."
  30.         );
  31.     object? ComputeCachedNavigationInstance() => GetPageInstanceFromCache(viewItem.TargetPageType);
  32. }
复制代码
可以看到,如果提供了serviceProvider或者pageService,就可以通过容器获取View实例,不需要通过NavigationViewActivator.CreateInstance创建实例了。
提供ServiceProvider,例如使用Prism:
  1. public class PrismServiceProvider : IServiceProvider
  2. {
  3.     private readonly IContainerProvider _containerProvider;
  4.     public PrismServiceProvider(IContainerProvider containerProvider)
  5.     {
  6.         _containerProvider = containerProvider;
  7.     }
  8.     public object GetService(Type serviceType)
  9.     {
  10.         return _containerProvider.Resolve(serviceType);
  11.     }
  12. }
复制代码
WPFUI中未提供默认的IPageService实现,但demo.mvvm中提供了基于IServiceProvider的实现,可以参考。本文基于Prism实现:
  1. public class PageService : IPageService
  2. {
  3.     private readonly IContainerProvider _containerProvider;
  4.     public PageService(IContainerProvider containerProvider)
  5.     {
  6.         _containerProvider = containerProvider;
  7.     }
  8.     public T GetPage<T>() where T : class
  9.     {
  10.         if (!typeof(FrameworkElement).IsAssignableFrom(typeof(T)))
  11.             throw new InvalidOperationException("The page should be a WPF control.");
  12.         return (T)_containerProvider.Resolve(typeof(T));
  13.     }
  14.     public FrameworkElement GetPage(Type pageType)
  15.     {
  16.         if (!typeof(FrameworkElement).IsAssignableFrom(pageType))
  17.             throw new InvalidOperationException("The page should be a WPF control.");
  18.         return _containerProvider.Resolve(pageType) as FrameworkElement;
  19.     }
  20. }
复制代码
最后一步,将PrismServiceProvider、PageService注入容器,并通过INavigationService为NavigationView设置IServiceProvider和IPageService:
  1. // App.xaml.cs
  2. protected override void RegisterTypes(IContainerRegistry containerRegistry)
  3. {
  4.     var serviceProvider = new PrismServiceProvider(Container);
  5.     containerRegistry.RegisterInstance<IServiceProvider>(serviceProvider);
  6.     containerRegistry.RegisterSingleton<IPageService, PageService>();
  7.     containerRegistry.RegisterSingleton<INavigationService, NavigationService>();
  8. }
  9. // MainWindow.xaml.cs
  10. public MainWindow(INavigationService navigationService,
  11.     IPageService pageService,
  12.     ISnackbarService snackbarService)
  13. {
  14.     InitializeComponent();
  15.     navigationService.SetPageService(pageService);
  16.     navigationService.SetNavigationControl(NavigationView);
  17. }
复制代码
来源:https://www.cnblogs.com/louzixl/p/18346088
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具