在Prism.Windows 7.1.0中创建Shell的替代方法?

时间:2018-10-22 10:12:14

标签: uwp prism dryioc

撰写本文时,MyGet Package中即将推出的Prism.Windows 7.1.0缺少重写方法 CreateShell() 我真的很想知道它是否将被转移到另一种方法中,或者将在最终版本中消失。

如果是这样,假设代码来自此tutorial并使用DryIoC容器,则实现shell视图的替代解决方案是什么。

1 个答案:

答案 0 :(得分:0)

您可以使用CreateShell()内的NavigationService来代替使用NavigationView替代。此答案中提供的代码是从三个Template10 Samples中的一个改编而来的,在撰写本文时,这三个Prism Samples尚未迁移到Sample Project (16299)Prism.Unity.Windows。应该注意的是,此答​​案使用了Prism.DryIoc.Windows,但是我认为可以轻松地将其交换为this或其他任何受支持的框架,而不会引起问题。

App.xaml

<prism:PrismApplication
    x:Class="StudentRecords.Uwp.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:prism="using:Prism.Unity">

</prism:PrismApplication>

App.xaml.cs

using System.Threading.Tasks;
using Prism;
using Prism.Ioc;
using Prism.Unity;
using StudentRecords.Repositories;
using StudentRecords.Services;
using StudentRecords.Uwp.ViewModels;
using StudentRecords.Uwp.Pages;
using Windows.UI.Xaml;

namespace StudentRecords.Uwp
{
    sealed partial class App : PrismApplication
    {
        public App() => InitializeComponent();

        public override void RegisterTypes(IContainerRegistry container)
        {
            container.RegisterSingleton<AppShell, AppShell>();

            container.RegisterSingleton<IStudentService, StudentService>();

            container.RegisterSingleton<IStudentRepository, MockStudentRepository>();

            container.RegisterForNavigation<HomePage, HomePageViewModel>("Home");
            container.RegisterForNavigation<LecturersPage, LecturersPageViewModel>("Lecturers");
            container.RegisterForNavigation<SettingsPage, SettingsPageViewModel>("Settings");
            container.RegisterForNavigation<StudentsPage, StudentsPageViewModel>("Students");
        }

        public override void OnInitialized() { }

        public override async Task OnStartAsync(StartArgs args)
        {
            var appShell = Container.Resolve<AppShell>();
            Window.Current.Content = appShell;

            await appShell.NavigationView.InitializeAsync();
            var navigationService = appShell.NavigationView.NavigationService;
        }
    }
}

AppShell.xaml

<Page
    x:Class="StudentRecords.Uwp.AppShell"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:controls="using:StudentRecords.Uwp.Views"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <controls:PrismNavigationView x:FieldModifier="public" x:Name="NavigationView">
        <NavigationView.MenuItems>
            <NavigationViewItem controls:PrismNavigationViewProperties.NavigationUri="/Home" controls:PrismNavigationViewProperties.IsStartPage="True" Content="Home">
                <NavigationViewItem.Icon>
                    <FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE80F;" />
                </NavigationViewItem.Icon>
            </NavigationViewItem>

            <NavigationViewItemSeparator />

            <NavigationViewItem controls:PrismNavigationViewProperties.NavigationUri="/Students" Content="Students">
                <NavigationViewItem.Icon>
                    <FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE716;" />
                </NavigationViewItem.Icon>
            </NavigationViewItem>

            <NavigationViewItem controls:PrismNavigationViewProperties.NavigationUri="/Lecturers" Content="Lecturers">
                <NavigationViewItem.Icon>
                    <FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE7BE;" />
                </NavigationViewItem.Icon>
            </NavigationViewItem>
        </NavigationView.MenuItems>
    </controls:PrismNavigationView>
</Page>

AppShell.xaml.cs

using Windows.UI.Xaml.Controls;

namespace StudentRecords.Uwp
{
    public sealed partial class AppShell : Page
    {
        public AppShell() => InitializeComponent();
    }
}

PrismNavigationView.cs

using Prism.Navigation;
using Prism.Services;
using System;
using System.Linq;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace StudentRecords.Uwp.Views
{
    public class PrismNavigationView : NavigationView
    {
        public event EventHandler SettingsInvoked;

        public PrismNavigationView()
        {
            Content = ContentFrame = new Frame();

            ContentFrame.Navigated += ContentFrame_NavigatedAsync;

            NavigationService = Prism.Navigation.NavigationService.Create(ContentFrame, Gesture.Back, Gesture.Forward, Gesture.Refresh) as IPlatformNavigationService;

            ItemInvoked += PrismNavigationView_ItemInvokedAsync;

            Loaded += PrismNavigationView_Loaded;
        }

        public IPlatformNavigationService NavigationService { get; }

        public string SettingsUri { get; set; } = "/Settings";

        private Frame ContentFrame { get; }

        private async void ContentFrame_NavigatedAsync(object sender, NavigationEventArgs e)
        {
            if (TryFindItem(e.SourcePageType, e.Parameter, out var item))
            {
                await SetSelectedItemAsync(item);
            }
        }

        private NavigationViewItem FindItem(string content) => MenuItems.OfType<NavigationViewItem>().SingleOrDefault(i => i.Content.Equals(content));

        public async Task<IPlatformNavigationService> InitializeAsync()
        {
            var item = MenuItems.OfType<NavigationViewItem>().SingleOrDefault(x => (bool)x.GetValue(PrismNavigationViewProperties.IsStartPageProperty));

            if (item != null)
            {
                await SetSelectedItemAsync(item);
            }

            return NavigationService;
        }

        private bool IsItemRegistered(Type type) => PageRegistry.TryGetRegistration(type, out var info);

        private bool IsItemSettings(Type type, object parameter) => NavigationQueue.TryParse(SettingsUri, null, out var settings) && type == settings.Last().View && (string)parameter == settings.Last().QueryString;

        private void NavigationService_CanGoBackChanged(object sender, EventArgs e) => IsBackEnabled = NavigationService.CanGoBack();

        private async void PrismNavigationView_ItemInvokedAsync(NavigationView sender, NavigationViewItemInvokedEventArgs args) => await SetSelectedItemAsync(args.IsSettingsInvoked ? SettingsItem : FindItem(args.InvokedItem.ToString()));

        private void PrismNavigationView_Loaded(object sender, RoutedEventArgs e) => NavigationService.CanGoBackChanged += NavigationService_CanGoBackChanged;

        private async Task SetSelectedItemAsync(object selectedItem)
        {
            if (selectedItem == null)
            {
                SelectedItem = null;
            }
            else if (selectedItem == SettingsItem)
            {
                if (SettingsUri != null)
                {
                    await NavigationService.NavigateAsync(SettingsUri);

                    SelectedItem = selectedItem;
                }

                SettingsInvoked?.Invoke(this, EventArgs.Empty);
            }
            else if (selectedItem is NavigationViewItem item)
            {
                if (item.GetValue(PrismNavigationViewProperties.NavigationUriProperty) is string path)
                {
                    if ((await NavigationService.NavigateAsync(path)).Success)
                    {
                        SelectedItem = selectedItem;
                    }
                    else
                    {
                        throw new Exception($"{selectedItem}.{nameof(PrismNavigationViewProperties.NavigationUriProperty)} navigation failed.");
                    }
                }
                else
                {
                    throw new Exception($"{selectedItem}.{nameof(PrismNavigationViewProperties.NavigationUriProperty)} is not valid URI.");
                }
            }
        }

        private bool TryFindItem(Type type, object parameter, out object item)
        {
            if (!IsItemRegistered(type))
            {
                item = null;
                return false;
            }

            if (IsItemSettings(type, parameter))
            {
                item = SettingsItem;
                return true;
            }

            foreach (var menuItem in MenuItems.OfType<NavigationViewItem>().Select(i => new { Item = i, Path = i.GetValue(PrismNavigationViewProperties.NavigationUriProperty) as string }).Where(x => !string.IsNullOrEmpty(x.Path)))
            {
                if (NavigationQueue.TryParse(menuItem.Path, null, out var menuQueue) && Equals(menuQueue.Last().View, type))
                {
                    item = menuItem;
                    return true;
                }
            }

            item = null;
            return false;
        }
    }

    public partial class PrismNavigationViewProperties : DependencyObject
    {
        public static string GetNavigationUri(DependencyObject obj) => (string)obj.GetValue(NavigationUriProperty);
        public static void SetNavigationUri(DependencyObject obj, string value) => obj.SetValue(NavigationUriProperty, value);
        public static readonly DependencyProperty NavigationUriProperty = DependencyProperty.RegisterAttached("NavigationUri", typeof(string), typeof(NavigationView), new PropertyMetadata(null));

        public static bool GetIsStartPage(NavigationViewItem obj) => (bool)obj.GetValue(IsStartPageProperty);
        public static void SetIsStartPage(NavigationViewItem obj, bool value) => obj.SetValue(IsStartPageProperty, value);
        public static readonly DependencyProperty IsStartPageProperty = DependencyProperty.RegisterAttached("IsStartPage", typeof(bool), typeof(PrismNavigationViewProperties), new PropertyMetadata(false));
    }
}