首页 > 解决方案 > 如何从其他页面初始化 ShellView(Windows 模板工作室)

问题描述

Windows 模板工作室:参考链接

我用Navigation Pane Type 和Prism Pattern创建了一个项目,我有 Settings 和一些页面

这是 App.xaml.cs:

[Windows.UI.Xaml.Data.Bindable]
public sealed partial class App : PrismUnityApplication
{
    public App()
    {
        InitializeComponent();
    }

    protected override void ConfigureContainer()
    {
        // register a singleton using Container.RegisterType<IInterface, Type>(new ContainerControlledLifetimeManager());
        base.ConfigureContainer();
        Container.RegisterInstance<IResourceLoader>(new ResourceLoaderAdapter(new ResourceLoader()));
        Container.RegisterType<ISampleDataService, SampleDataService>();
    }

    protected override async Task OnLaunchApplicationAsync(LaunchActivatedEventArgs args)
    {
        await LaunchApplicationAsync(PageTokens.MainPage, null);
    }

    private async Task LaunchApplicationAsync(string page, object launchParam)
    {
        await ThemeSelectorService.SetRequestedThemeAsync();
        NavigationService.Navigate(page, launchParam);
        Window.Current.Activate();
    }

    protected override async Task OnActivateApplicationAsync(IActivatedEventArgs args)
    {
        await Task.CompletedTask;
    }

    protected override async Task OnInitializeAsync(IActivatedEventArgs args)
    {
        await base.OnInitializeAsync(args);
        await ThemeSelectorService.InitializeAsync().ConfigureAwait(false);

        //We are remapping the default ViewNamePage and ViewNamePageViewModel naming to ViewNamePage and ViewNameViewModel to
        //gain better code reuse with other frameworks and pages within Windows Template Studio
        ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) =>
        {
            var viewModelTypeName = string.Format(CultureInfo.InvariantCulture, "App1.ViewModels.{0}ViewModel, App1", viewType.Name.Substring(0, viewType.Name.Length - 4));
            return Type.GetType(viewModelTypeName);
        });
    }

    protected override IDeviceGestureService OnCreateDeviceGestureService()
    {
        var service = base.OnCreateDeviceGestureService();
        service.UseTitleBarBackButton = false;
        return service;
    }

    public void SetNavigationFrame(Frame frame)
    {
        var sessionStateService = Container.Resolve<ISessionStateService>();
        CreateNavigationService(new FrameFacadeAdapter(frame), sessionStateService);
    }

    protected override UIElement CreateShell(Frame rootFrame)
    {
        var shell = Container.Resolve<ShellPage>();
        shell.SetRootFrame(rootFrame);
        return shell;
    }
}

我想在显示ShellPage之前显示一个SignInPage,所以我在Views文件夹下创建了一个SignInPage ,并在ViewModels文件夹下创建了SignInPageViewModel类。

我试图将OnLaunchApplicationAsync更改为:

protected override async Task OnLaunchApplicationAsync(LaunchActivatedEventArgs args)
    {
        await LaunchApplicationAsync("SignIn", null);
    }

并删除了:

protected override UIElement CreateShell(Frame rootFrame)
    {
        var shell = Container.Resolve<ShellPage>();
        shell.SetRootFrame(rootFrame);
        return shell;
    }

现在我的应用程序启动页面是我的SignInPage,我在该页面上有LogInButton,并从我的 viewmodel 委托命令绑定了命令,但它无法找到我的 viewmodel(ViewModelLocator.AutoWireViewModel="True"),所以我在我的应用程序.xaml.cs:

protected override void ConfigureViewModelLocator()
    {
        base.ConfigureViewModelLocator();

        ViewModelLocationProvider.Register<SignInPage, ViewModels.SignInPageViewModel>();
    }

问题 1:为什么它无法找到我的视图模型,即使它与自动创建的页面具有相同的命名空间?

现在按钮命令是导航到ShellPage,所以每当我单击按钮时,它将导航到ShellPage但 Frame 未正确初始化,因此当我尝试导航到任何页面时出现空引用错误。

问题 2:如何在导航时初始化 ShellPage?

标签: c#uwpprismnavigationviewwindows-template-studio

解决方案


问题可能出在您的命名中。

更改SignInPageViewModelSignInViewModel

protected override async Task OnInitializeAsync(IActivatedEventArgs args)
{
    await base.OnInitializeAsync(args);

    //We are remapping the default ViewNamePage and ViewNamePageViewModel naming to ViewNamePage and ViewNameViewModel to
    //gain better code reuse with other frameworks and pages within Windows Template Studio
    ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) =>
    {
        var viewModelTypeName = string.Format(CultureInfo.InvariantCulture, "App1.ViewModels.{0}ViewModel, App1", viewType.Name.Substring(0, viewType.Name.Length - 4));
        return Type.GetType(viewModelTypeName);
    });
}

请注意这个函数,用于注册当前页面的ViewModel。根据相应的命名约定,如果 Page 的名称是{name}Page.xaml,那么 ViewModel 就是{name}ViewModel.cs


更新

如何在导航时初始化 ShellPage?

坦率地说,这种行为不适合当前的架构。因为默认情况下,应用程序只有一个rootFrame,但是由于你去掉了CreateShell方法的override,势必会引入第二个frame,这会导致未知错误。

session state如果你坚持,我这里提供了一个方法,但是当软件关闭时它不会正确保存。

应用程序.xaml.cs

public static App Instance;
public App()
{
    InitializeComponent();
    Instance = this;
}

登录页面.xaml.cs

SignInButton_Click请在 xaml 中收听事件

private void SignInButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
    var rootFrame = Window.Current.Content as Frame;
    var frame = new Frame();
    App.Instance.SetNavigationFrame(frame);
    rootFrame.Navigate(typeof(ShellPage), frame);
}

ShellPage.xaml.cs

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    if(e.Parameter is Frame frame)
    {
        SetRootFrame(frame);
        frame.Navigate(typeof(MainPage));
    }
}

此致。


推荐阅读