日立电梯戴先生 发表于 2024-8-6 23:10:01

WPFUI报错 - page does not have a parameterless constructor

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报错。
问题处理

查看异常堆栈,找报错位置:
在 Wpf.Ui.Controls.NavigationViewActivator.CreateInstance(Type pageType, Object dataContext) 在 Wpf.Ui.Controls\NavigationViewActivator.cs 中: 第 37 行
在 Wpf.Ui.Controls.NavigationView.GetPageInstanceFromCache(Type targetPageType) 在 Wpf.Ui.Controls\NavigationView.cs 中: 第 1206 行
在 Wpf.Ui.Controls.NavigationCache.Remember(Type entryType, NavigationCacheMode cacheMode, Func`1 generate) 在 Wpf.Ui.Controls\NavigationCache.cs 中: 第 25 行
在 Wpf.Ui.Controls.NavigationView.GetNavigationItemInstance(INavigationViewItem viewItem) 在 Wpf.Ui.Controls\NavigationView.cs 中: 第 1185 行
在 Wpf.Ui.Controls.NavigationView.NavigateInternal(INavigationViewItem viewItem, Object dataContext, Boolean addToNavigationStack, Boolean isBackwardsNavigated) 在 Wpf.Ui.Controls\NavigationView.cs 中: 第 1131 行
在 Wpf.Ui.Controls.NavigationViewItem.OnClick() 在 Wpf.Ui.Controls\NavigationViewItem.cs 中: 第 314 行
...看源码,找解决方案:
private object GetNavigationItemInstance(INavigationViewItem viewItem)
{
    if (viewItem.TargetPageType is null)
    {
      throw new InvalidOperationException(
            $"The {nameof(viewItem)}.{nameof(viewItem.TargetPageType)} property cannot be null."
      );
    }

    if (_serviceProvider is not null)
    {
      return _serviceProvider.GetService(viewItem.TargetPageType)
            ?? throw new InvalidOperationException(
                $"{nameof(_serviceProvider)}.{nameof(_serviceProvider.GetService)} returned null for type {viewItem.TargetPageType}."
            );
    }

    if (_pageService is not null)
    {
      return _pageService.GetPage(viewItem.TargetPageType)
            ?? throw new InvalidOperationException(
                $"{nameof(_pageService)}.{nameof(_pageService.GetPage)} returned null for type {viewItem.TargetPageType}."
            );
    }

    return _cache.Remember(
            viewItem.TargetPageType,
            viewItem.NavigationCacheMode,
            ComputeCachedNavigationInstance
      )
      ?? throw new InvalidOperationException(
            $"Unable to get or create instance of {viewItem.TargetPageType} from cache."
      );

    object? ComputeCachedNavigationInstance() => GetPageInstanceFromCache(viewItem.TargetPageType);
}可以看到,如果提供了serviceProvider或者pageService,就可以通过容器获取View实例,不需要通过NavigationViewActivator.CreateInstance创建实例了。
提供ServiceProvider,例如使用Prism:
public class PrismServiceProvider : IServiceProvider
{
    private readonly IContainerProvider _containerProvider;

    public PrismServiceProvider(IContainerProvider containerProvider)
    {
      _containerProvider = containerProvider;
    }

    public object GetService(Type serviceType)
    {
      return _containerProvider.Resolve(serviceType);
    }
}WPFUI中未提供默认的IPageService实现,但demo.mvvm中提供了基于IServiceProvider的实现,可以参考。本文基于Prism实现:
public class PageService : IPageService
{
    private readonly IContainerProvider _containerProvider;

    public PageService(IContainerProvider containerProvider)
    {
      _containerProvider = containerProvider;
    }

    public T GetPage<T>() where T : class
    {
      if (!typeof(FrameworkElement).IsAssignableFrom(typeof(T)))
            throw new InvalidOperationException("The page should be a WPF control.");

      return (T)_containerProvider.Resolve(typeof(T));
    }

    public FrameworkElement GetPage(Type pageType)
    {
      if (!typeof(FrameworkElement).IsAssignableFrom(pageType))
            throw new InvalidOperationException("The page should be a WPF control.");

      return _containerProvider.Resolve(pageType) as FrameworkElement;
    }
}最后一步,将PrismServiceProvider、PageService注入容器,并通过INavigationService为NavigationView设置IServiceProvider和IPageService:
// App.xaml.cs
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    var serviceProvider = new PrismServiceProvider(Container);
    containerRegistry.RegisterInstance<IServiceProvider>(serviceProvider);
    containerRegistry.RegisterSingleton<IPageService, PageService>();
    containerRegistry.RegisterSingleton<INavigationService, NavigationService>();
}

// MainWindow.xaml.cs
public MainWindow(INavigationService navigationService,
    IPageService pageService,
    ISnackbarService snackbarService)
{
    InitializeComponent();

    navigationService.SetPageService(pageService);
    navigationService.SetNavigationControl(NavigationView);
}
来源:https://www.cnblogs.com/louzixl/p/18346088
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: WPFUI报错 - page does not have a parameterless constructor