Xamarin.Forms - Master/detail 页面和导航历史问题
Xamarin.Forms - Master/detail page and navigation history issue
我有一个应用程序使用 masterdetail 页面在所有页面中显示菜单。在我的应用程序中,导航以两种方式发生。一种来自菜单,第二种来自仪表板。所以如果我导航到另一个页面,然后按 "BACK" 按钮,它会关闭应用程序。它不记得导航历史。
主详情页面如下:
public class RootPage : MasterDetailPage
{
public RootPage ()
{
var menuPage = new MenuPage ();
menuPage.Menu.ItemSelected += (sender, e) => NavigateTo (e.SelectedItem as MenuItem);
Master = menuPage;
Detail = new NavigationPage (new ContractsPage ());
}
void NavigateTo (MenuItem menu)
{
Page displayPage = (Page)Activator.CreateInstance (menu.TargetType);
Detail = new NavigationPage (displayPage);
IsPresented = false;
}
}
有什么办法可以解决这个问题吗?
这里的问题是您没有使用导航堆栈来执行页面转换,而是替换了您自己页面上的项目,因此 "back" 除了导航到您的 MasterDetailPage。
您可以通过创建一个继承 MasterDetailPage 并初始化菜单的新 MenuMasterDetail.cs class 来解决问题,然后创建从您的通用基础继承的 MenuItem_A_Page.xaml(或 .cs)在您的共同基础 class 中,您将使用 Navigation.PushAsync(...)
在页面之间转换。
基础class:
public class MenuDetailPage: MasterDetailPage{
public MenuDetailPage(): base(){
this.Master = BuildMyMenuListHere(); // the menu items will also define navigation targets
}
}
subclass 在 CS:
public class FirstDetailWithMenuPage: MenuDetailPage{
public FirstDetailWithMenuPage()
: base() // this creates the menu
{
this.Detail = new StackLayout{ // change this however you need
Children = {
new Label { Text = "This is the first page" },
new Button { Text= "Ok"},
}
}
}
Subclass in XAML(连同上面的CS,减去设置Detail的部分):
<local:FirstDetailWithMenuPage namespace:YourNamespace;assembly=YourAssemblyName" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:local="clr-n xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="FirstDetailWithMenuPage">
<local:FirstDetailWithMenuPage.Detail>
...
同时将您的 App.cs 更新为 return 导航页面,其中包含您拥有的第一个 master/detail 页面(不是基础页面):
App.cs:
public static Page GetMainPage ()
{
return new NavigationPage(new FirstDetailWithMenuPage());
}
就像@Sten-Petrov说的:你是在替换详情页,并没有触发历史机制。要触发历史记录机制,您需要在详细信息页面的导航 属性 上执行 PushAsync(Page)。
在您的示例中,将 NavigateTo 更改为:
void NavigateTo (MenuItem menu)
{
Page displayPage = (Page)Activator.CreateInstance (menu.TargetType);
Detail.Navigation.PushAsync(displayPage);
}
这不会替换内容,但会打开一个具有您想要的后退按钮功能的新页面。
如果您希望 Master-Detail 页面具有后退按钮功能,那么您需要自定义后退堆栈过程,在我看来,这是不值得的。在这种情况下,只需移动到不同的 page/navigation 结构即可。
我遇到了同样的问题,Detail.Navigation.PushAsync(itemSelected)
制作了 汉堡包 菜单 消失 并且还创建了另一个子 class 保留似乎在代码和性能方面的大量工作。因此,我决定将自己的堆栈数据类型用于主详细信息页面。跟踪和编码有点棘手,但工作正常。
在应用程序加载时使用当前详细信息页面初始化它,并针对每个选定的项目将新页面推送到堆栈顶部。
public partial class MyMasterDetailPage: MasterDetailPage
{
private Stack navigationStack = new Stack();
public MyMasterDetailPage()
{
InitializeComponent();
navigationStack.Push(Detail);
try
{
masterPage.listView.ItemSelected += OnItemSelected;
}
catch (Exception exc)
{
System.Diagnostics.Debug.WriteLine(exc.Message);
}
}
在
后面的相同页面代码中覆盖 OnBackButtonPressed()
protected override bool OnBackButtonPressed()
{
try
{
var lastPage = navigationStack.Pop();
if (lastPage.Equals(Detail))
lastPage = navigationStack.Pop();
Detail = (Page)lastPage;
IsPresented = false;
// to avoid app close when complete pop and new page is push on top of it
if (navigationStack.Count == 0)
navigationStack.Push(Detail);
return true;
}
catch (Exception)
{
return base.OnBackButtonPressed();
}
}
我有一个应用程序使用 masterdetail 页面在所有页面中显示菜单。在我的应用程序中,导航以两种方式发生。一种来自菜单,第二种来自仪表板。所以如果我导航到另一个页面,然后按 "BACK" 按钮,它会关闭应用程序。它不记得导航历史。 主详情页面如下:
public class RootPage : MasterDetailPage
{
public RootPage ()
{
var menuPage = new MenuPage ();
menuPage.Menu.ItemSelected += (sender, e) => NavigateTo (e.SelectedItem as MenuItem);
Master = menuPage;
Detail = new NavigationPage (new ContractsPage ());
}
void NavigateTo (MenuItem menu)
{
Page displayPage = (Page)Activator.CreateInstance (menu.TargetType);
Detail = new NavigationPage (displayPage);
IsPresented = false;
}
}
有什么办法可以解决这个问题吗?
这里的问题是您没有使用导航堆栈来执行页面转换,而是替换了您自己页面上的项目,因此 "back" 除了导航到您的 MasterDetailPage。
您可以通过创建一个继承 MasterDetailPage 并初始化菜单的新 MenuMasterDetail.cs class 来解决问题,然后创建从您的通用基础继承的 MenuItem_A_Page.xaml(或 .cs)在您的共同基础 class 中,您将使用 Navigation.PushAsync(...)
在页面之间转换。
基础class:
public class MenuDetailPage: MasterDetailPage{
public MenuDetailPage(): base(){
this.Master = BuildMyMenuListHere(); // the menu items will also define navigation targets
}
}
subclass 在 CS:
public class FirstDetailWithMenuPage: MenuDetailPage{
public FirstDetailWithMenuPage()
: base() // this creates the menu
{
this.Detail = new StackLayout{ // change this however you need
Children = {
new Label { Text = "This is the first page" },
new Button { Text= "Ok"},
}
}
}
Subclass in XAML(连同上面的CS,减去设置Detail的部分):
<local:FirstDetailWithMenuPage namespace:YourNamespace;assembly=YourAssemblyName" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:local="clr-n xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="FirstDetailWithMenuPage">
<local:FirstDetailWithMenuPage.Detail>
...
同时将您的 App.cs 更新为 return 导航页面,其中包含您拥有的第一个 master/detail 页面(不是基础页面):
App.cs:
public static Page GetMainPage ()
{
return new NavigationPage(new FirstDetailWithMenuPage());
}
就像@Sten-Petrov说的:你是在替换详情页,并没有触发历史机制。要触发历史记录机制,您需要在详细信息页面的导航 属性 上执行 PushAsync(Page)。
在您的示例中,将 NavigateTo 更改为:
void NavigateTo (MenuItem menu)
{
Page displayPage = (Page)Activator.CreateInstance (menu.TargetType);
Detail.Navigation.PushAsync(displayPage);
}
这不会替换内容,但会打开一个具有您想要的后退按钮功能的新页面。
如果您希望 Master-Detail 页面具有后退按钮功能,那么您需要自定义后退堆栈过程,在我看来,这是不值得的。在这种情况下,只需移动到不同的 page/navigation 结构即可。
我遇到了同样的问题,Detail.Navigation.PushAsync(itemSelected)
制作了 汉堡包 菜单 消失 并且还创建了另一个子 class 保留似乎在代码和性能方面的大量工作。因此,我决定将自己的堆栈数据类型用于主详细信息页面。跟踪和编码有点棘手,但工作正常。
在应用程序加载时使用当前详细信息页面初始化它,并针对每个选定的项目将新页面推送到堆栈顶部。
public partial class MyMasterDetailPage: MasterDetailPage
{
private Stack navigationStack = new Stack();
public MyMasterDetailPage()
{
InitializeComponent();
navigationStack.Push(Detail);
try
{
masterPage.listView.ItemSelected += OnItemSelected;
}
catch (Exception exc)
{
System.Diagnostics.Debug.WriteLine(exc.Message);
}
}
在
后面的相同页面代码中覆盖OnBackButtonPressed()
protected override bool OnBackButtonPressed()
{
try
{
var lastPage = navigationStack.Pop();
if (lastPage.Equals(Detail))
lastPage = navigationStack.Pop();
Detail = (Page)lastPage;
IsPresented = false;
// to avoid app close when complete pop and new page is push on top of it
if (navigationStack.Count == 0)
navigationStack.Push(Detail);
return true;
}
catch (Exception)
{
return base.OnBackButtonPressed();
}
}