Невозможно обернуть MasterDetailPage в NavigationPage с помощью Prism.Forms Xamarin для отображения кнопки «Назад». - PullRequest
0 голосов
/ 24 сентября 2019

Я использовал проект Xamarin.Forms по умолчанию и пытался преобразовать их с помощью Prism.Forms.

Мне удалось, чтобы он работал, чтобы показать MenuPage в SplitView и ItemsPage насодержимое NavigateAsync("MainPage/ItemsPage") в файле App.xaml.cs.

В дальнейшем я заметил, что при переходе на новую страницу не отображается кнопка «Назад» в приложении UWP, и я прочитал, что янужно обернуть MainPage в NavigationPage, поэтому я попытался сделать это, зарегистрировав NavigationPage в контейнере и NavigateAsync("NavigationPage/MainPage/ItemsPage"),, но, к сожалению, я получаю пустой пользовательский интерфейс.

Что я сделал не так здесь?

Я могу предоставить больше кода, если этого недостаточно.

В App.xaml.cs

protected override void OnInitialized()
{
    this.InitializeComponent();


    var navigationPage = $"{nameof(NavigationPage)}/{nameof(Views.MainPage)}/{nameof(ItemsPage)}";    // why does this shows blank UI?
    var navigationPage2 = $"{nameof(Views.MainPage)}/{nameof(Views.ItemsPage)}"; // this shows MenuPage on the menu and items page on the main content.
    _ = this.NavigationService.NavigateAsync($"{navigationPage}");
}

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    containerRegistry.RegisterForNavigation<NavigationPage>(nameof(NavigationPage));
    containerRegistry.RegisterForNavigation<AboutPage>(nameof(AboutPage));
    containerRegistry.RegisterForNavigation<ItemDetailPage>(nameof(ItemDetailPage));
    containerRegistry.RegisterForNavigation<ItemsPage>(nameof(ItemsPage));
    containerRegistry.RegisterForNavigation<MainPage>(nameof(MainPage));
    containerRegistry.RegisterForNavigation<MenuPage>(nameof(MenuPage));
    containerRegistry.RegisterForNavigation<NewItemPage>(nameof(NewItemPage));
}

в MainPage.xaml (это MasterDetailPage)

<?xml version="1.0" encoding="utf-8" ?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
            xmlns:d="http://xamarin.com/schemas/2014/forms/design"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            mc:Ignorable="d"
            xmlns:views="clr-namespace:XamarinApp.Views"
            x:Class="XamarinApp.Views.MainPage">

    <MasterDetailPage.Master>
        <views:MenuPage />
    </MasterDetailPage.Master>

</MasterDetailPage>

в MenuPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:b="clr-namespace:XamarinApp.Behaviors"
             xmlns:prism="http://prismlibrary.com"
             mc:Ignorable="d"
             x:Class="XamarinApp.Views.MenuPage"
             prism:ViewModelLocator.AutowireViewModel="True"
             Title="Menu">

    <StackLayout VerticalOptions="FillAndExpand">
        <ListView
            x:Name="ListViewMenu"
            HasUnevenRows="True"
            ItemsSource="{Binding MenuItems, Mode=OneTime}"
            SelectedItem="{Binding SelectedMenuItem, Mode=TwoWay}">
            <ListView.Behaviors>
                <b:EventToCommandBehavior
                    EventName="ItemSelected"
                    Command="{Binding ItemSelectedCommand, Mode=OneTime}"/>
            </ListView.Behaviors>
            <d:ListView.ItemsSource>
                <x:Array Type="{x:Type x:String}">
                    <x:String>Item 1</x:String>
                    <x:String>Item 2</x:String>
                </x:Array>
            </d:ListView.ItemsSource>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Grid Padding="10">
                            <Label Text="{Binding Title}" d:Text="{Binding .}" FontSize="20"/>
                        </Grid>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>

</ContentPage>

В ItemsPage.xaml (хотя это не актуально)

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:b="clr-namespace:XamarinApp.Behaviors"
             xmlns:prism="http://prismlibrary.com"
             mc:Ignorable="d"
             x:Class="XamarinApp.Views.ItemsPage"
             Title="{Binding Title}"
             x:Name="BrowseItemsPage"
             prism:ViewModelLocator.AutowireViewModel="True">

    <ContentPage.Behaviors>
        <b:EventToCommandBehavior
            EventName="Appearing"
            Command="{Binding LoadItemsCommand, Mode=OneTime}"/>
    </ContentPage.Behaviors>

    <ContentPage.ToolbarItems>
        <ToolbarItem Text="Add" Command="{Binding AddItemCommand, Mode=OneTime}"/>
    </ContentPage.ToolbarItems>

    <StackLayout Grid.Row="1">
        <ListView
            x:Name="ItemsListView"
            ItemsSource="{Binding Items, Mode=OneWay}"
            SelectedItem="{Binding SelectedItem,Mode=TwoWay}"
            VerticalOptions="FillAndExpand"
            HasUnevenRows="true"
            RefreshCommand="{Binding LoadItemsCommand, Mode=OneTime}"
            IsPullToRefreshEnabled="true"
            IsRefreshing="{Binding IsBusy, Mode=OneWay}"
            CachingStrategy="RecycleElement">
            <ListView.Behaviors>
                <b:EventToCommandBehavior
                    EventName="ItemSelected"
                    Command="{Binding OnItemSelectedCommand, Mode=OneTime}"/>
            </ListView.Behaviors>
            <d:ListView.ItemsSource>
                <x:Array Type="{x:Type x:String}">
                    <x:String>First Item</x:String>
                    <x:String>Second Item</x:String>
                    <x:String>Third Item</x:String>
                    <x:String>Forth Item</x:String>
                    <x:String>Fifth Item</x:String>
                    <x:String>Sixth Item</x:String>
                </x:Array>
            </d:ListView.ItemsSource>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout Padding="10">
                            <Label Text="{Binding Text}" 
                                d:Text="{Binding .}"
                                LineBreakMode="NoWrap" 
                                Style="{DynamicResource ListItemTextStyle}" 
                                FontSize="16" />
                            <Label Text="{Binding Description}" 
                                d:Text="Item descripton"
                                LineBreakMode="NoWrap"
                                Style="{DynamicResource ListItemDetailTextStyle}"
                                FontSize="13" />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>

</ContentPage>

В ItemsPageViewModel.cs

private readonly INavigationService navigationService;
private ObservableCollection<Item> items;
private Item selectedItem;

public ItemsPageViewModel()
{
    this.Title = "Browse";
    this.Items = new ObservableCollection<Item>();
    this.LoadItemsCommand = new DelegateCommand(this.LoadItems, this.CanLoadItems).ObservesProperty(() => this.Items);
    this.OnItemSelectedCommand = new DelegateCommand(this.OnItemsSelected_Execute, this.OnItemsSelected_CanExecute).ObservesProperty(() => this.SelectedItem);
    this.AddItemCommand = new DelegateCommand(this.AddItem);

}

public ItemsPageViewModel(INavigationService navigationService)
    : this()
{
    this.navigationService = navigationService;
}

public ObservableCollection<Item> Items
{
    get => this.items;
    set => this.SetProperty(ref this.items, value);
}

public Item SelectedItem
{
    get => this.selectedItem;
    set => this.SetProperty(ref this.selectedItem, value);
}

public ICommand AddItemCommand { get; }

public ICommand OnItemSelectedCommand { get; }

public ICommand LoadItemsCommand { get; }

private bool CanLoadItems()
{
    return !(this.Items?.Any() ?? false);
}

private async void LoadItems()
{
    if (this.IsBusy)
    {
        return;
    }

    this.IsBusy = true;

    try
    {
        this.Items.Clear();
        var items = await this.DataStore.GetItemsAsync(true);
        foreach (var item in items)
        {
            this.Items.Add(item);
        }
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex);
    }
    finally
    {
        this.IsBusy = false;
    }
}

private bool OnItemsSelected_CanExecute()
{
    return this.SelectedItem != null;
}

private async void OnItemsSelected_Execute()
{
    var parameters = new NavigationParameters
    {
        { "hash", this.selectedItem.ToString() },
    };

    await this.navigationService.NavigateAsync($"{nameof(ItemDetailPage)}", parameters);
    // When I navigated to the ItemDetailPage, I do not see the (SplitView/HamburgerMenu) PageMenu
    // and I do not see Back button

    // Manually deselect item.
    this.SelectedItem = null;
}

private async void AddItem()
{
    await this.navigationService.NavigateAsync($"{nameof(NewItemPage)}");
}

1 Ответ

0 голосов
/ 25 сентября 2019

Я нашел свой ответ:

  1. Мы не должны заключать MasterDetailPage в NavigationPage.Вместо этого оберните содержимое на странице навигации, где вы хотите, чтобы появилась кнопка «Назад».В моем случае мне нужно обернуть ItemsPage в Navigation

В App.xaml.cs

var navigationPage = $"{nameof(Views.MainPage)}/{nameof(NavigationPage)}/{nameof(ItemsPage)}";
_ = this.NavigationService.NavigateAsync($"{navigationPage}");
В ItemsPageViewModel мне нужно только перейти на целевую страницу без указания MainPage и NavigationPage, поэтому появится кнопка «Назад» (с сохранением меню «Гамбургер»)

В ItemsPageViewModel.cs

// keep this code intact from example above to navigate, have a back button on the new page, and also keep the hamburger menu intact.
await this.navigationService.NavigateAsync($"{nameof(ItemDetailPage)}", parameters);
В MenuPageViewModel я бы настроил навигацию так, чтобы меню гамбургера всегда отображалось без изменений:

В MenuPageViewModel.cs

private async void ItemSelectedHandler()
{
    if (this.SelectedMenuItem == null)
    {
        return;
    }

    var id = this.SelectedMenuItem.Id;
    switch (id)
    {
        case MenuItemType.Browse:
            // re-show the MenuPage in HamburgerMenu and wrap ItemsPage in NavigationPage.
            // However, navigating with this method will not show the back button in the new page.
            await this.navigationService.NavigateAsync($"/{nameof(MainPage)}/{nameof(NavigationPage)}/{nameof(ItemsPage)}");
            break;
        case MenuItemType.About:
            // re-show the MenuPage in HamburgerMenu and wrap ItemsPage in NavigationPage.
            // However, navigating with this method will not show the back button in the new page.
            await this.navigationService.NavigateAsync($"/{nameof(MainPage)}/{nameof(NavigationPage)}/{nameof(AboutPage)}");
            break;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...