无法使用 Prism.Forms Xamarin 在导航页面中包装 MasterDetailsPage 以显示"



我使用了默认的Xamarin.Forms项目,并尝试使用Prism.Forms转换它们。

我设法通过 App.xaml.cs 中的NavigateAsync("MainPage/ItemsPage")来显示SplitView中的MenuPage和内容ItemsPage

展望未来,我注意到当我导航到新页面时,UWP 应用程序上没有显示"后退"按钮,并且我读到我需要将MainPage包装在NavigationPage中,所以我尝试通过将NavigationPage注册到容器并NavigateAsync("NavigationPage/MainPage/ItemsPage"),来执行此操作,但不幸的是我得到了空白 UI。

我在这里做错了什么?

如果这还不够,我可以提供更多代码。

在 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 中(这是 MasterDetailsPage(

<?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>

in 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>

在"项目页面视图模型"中.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. 我们不应该将 MasterDetailsPage 包装在导航页面中。而是将内容包装在导航页面中,您希望显示"后退"按钮的位置。就我而言,我需要在导航中包装项目页面

在 App.xaml 中.cs

var navigationPage = $"{nameof(Views.MainPage)}/{nameof(NavigationPage)}/{nameof(ItemsPage)}";
_ = this.NavigationService.NavigateAsync($"{navigationPage}");
  1. 在项目页面视图模型中,我只需要导航到目标页面而不指定主页和导航页面,因此会出现后退按钮(并保持汉堡菜单不变(

在"项目页面视图模型"中.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);
  1. 在菜单页面视图模型中,我会通过以下方式调整导航以始终完整地显示汉堡菜单:

在菜单页面视图模型中.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;
}
}

最新更新