Prism 的INavigationService 并非旨在完成您想做的事情。幸运的是自定义视图!您可以按照之前的建议进行操作,但我通常会避免创建自定义页面,而是创建一个拥有自己的内容属性的自定义视图。
编辑:
这些术语可能会与 Xamarin Forms 混淆,尤其是如果您是 MVVM 和 Xamarin Forms 的新手,和/或已从其他平台上开发。
Xamarin Forms 所指的 View 在其他平台上通常被称为 Control。这在使用 Prism 等 MVVM 框架时尤其令人困惑,因为我们的 MVVM Views 实际上是 Xamarin Forms Pages。
虽然有时我们需要创建自定义类型的页面,但通常我们只是实现一些页面类型。例如,假设我有一个要用于登录页面的页面:
LoginPage.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"
Title="{Binding Title}"
x:Class="MyAwesomeApp.Views.LoginPage">
<Grid BackgroundColor="{DynamicResource primary}">
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="3*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Grid.Resources>
<ResourceDictionary>
<Style TargetType="StackLayout">
<Setter Property="BackgroundColor" Value="White" />
<Setter Property="VerticalOptions" Value="FillAndExpand" />
</Style>
<Style TargetType="Entry">
<Setter Property="Margin" Value="40,10" />
</Style>
<Style TargetType="Button">
<Setter Property="Margin" Value="20" />
<Setter Property="BackgroundColor" Value="{DynamicResource primaryDark}" />
<Setter Property="TextColor" Value="White" />
<Setter Property="BorderRadius" Value="5" />
<Setter Property="BorderWidth" Value="1" />
<Setter Property="BorderColor" Value="Black" />
</Style>
</ResourceDictionary>
</Grid.Resources>
<Image Source="logo.png"
Aspect="AspectFit"
HorizontalOptions="Center"
VerticalOptions="Center" />
<StackLayout Grid.Row="1">
<Entry Text="{Binding UserName}"
Placeholder="Enter your username"
x:Name="userNameEntry"
VerticalOptions="EndAndExpand" />
<Entry Text="{Binding Password}"
Placeholder="Enter your password"
IsPassword="True"
x:Name="passwordEntry"
VerticalOptions="StartAndExpand" />
<Button Text="Submit"
Command="{Binding LoginCommand}" />
</StackLayout>
</Grid>
</ContentPage>
LoginPage.xaml.cs
public partial class LoginPage
{
public LoginPage()
{
InitializeComponent();
}
}
虽然 XAML 中发生了很多事情,但这只是一个作为 ContentPage 的页面。无论如何,它不是自定义页面。您会注意到这里后面的代码中绝对没有任何内容。我可能会创建一些事件处理程序,例如,如果用户在键盘上点击 Done/Enter 以转到下一个字段或调用按钮单击,但这仍然不能使其成为自定义页面。
有关“自定义页面”的示例,您可以查看XLabs ExtendedTabbedPage。您会注意到的一件事是在他们的 TabbedPage 版本上有几个新属性。当然,他们的页面仅因renderer而有效
继续我已经展示的示例,假设我们想要采用我在页面中创建的登录布局,并希望能够跨项目重用它,或者可能在我的应用程序的不同页面上重用它。然后我想做类似的事情:
LoginView.xaml
<?xml version="1.0" encoding="UTF-8"?>
<Grid xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
BackgroundColor="{DynamicResource primary}"
x:Name="grid"
x:Class="MyAwesomeApp.Controls.LoginView">
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="3*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Grid.Resources>
<ResourceDictionary>
<Style TargetType="StackLayout">
<Setter Property="BackgroundColor" Value="White" />
<Setter Property="VerticalOptions" Value="FillAndExpand" />
</Style>
<Style TargetType="Entry">
<Setter Property="Margin" Value="40,10" />
</Style>
<Style TargetType="Button">
<Setter Property="Margin" Value="20" />
<Setter Property="BackgroundColor" Value="{DynamicResource primaryDark}" />
<Setter Property="TextColor" Value="White" />
<Setter Property="BorderRadius" Value="5" />
<Setter Property="BorderWidth" Value="1" />
<Setter Property="BorderColor" Value="Black" />
</Style>
</ResourceDictionary>
</Grid.Resources>
<Image Source="logo.png"
Aspect="AspectFit"
HorizontalOptions="Center"
VerticalOptions="Center" />
<StackLayout Grid.Row="1" BindingContext="{x:Reference grid}">
<Entry Text="{Binding UserName}"
Placeholder="Enter your username"
x:Name="userNameEntry"
VerticalOptions="EndAndExpand" />
<Entry Text="{Binding Password}"
Placeholder="Enter your password"
IsPassword="True"
x:Name="passwordEntry"
VerticalOptions="StartAndExpand" />
<Button Text="Submit"
Command="{Binding LoginCommand}" />
</StackLayout>
</Grid>
LoginView.xaml.cs
public partial class LoginView : Grid
{
public static readonly BindableProperty UserNameProperty =
BindableProperty.Create(nameof(UserName), typeof(string), typeof(LoginView), string.Empty);
public static readonly BindableProperty PasswordProperty =
BindableProperty.Create(nameof(Password), typeof(string), typeof(LoginView), string.Empty);
public static readonly BindableProperty LoginCommandProperty =
BindableProperty.Create(nameof(LoginCommand), typeof(ICommand), typeof(LoginView), null);
public LoginView()
{
InitializeComponent();
}
public string UserName
{
get { return (string)GetValue(UserNameProperty); }
set { SetValue(UserNameProperty,value); }
}
public string Password
{
get { return (string)GetValue(PasswordProperty); }
set { SetValue(PasswordProperty, value); }
}
public ICommand LoginCommand
{
get { return (ICommand)GetValue(LoginCommandProperty); }
set { SetValue(LoginCommandProperty, value); }
}
}
重构的 LoginPage.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:controls="clr-namespace:MyAwesomeApp.Controls"
Title="{Binding Title}"
x:Class="MyAwesomeApp.Views.LoginPage">
<controls:LoginView UserName="{Binding UserName}"
Password="{Binding Password}"
LoginCommand="{Binding LoginCommand}" />
</ContentPage>
LoginView 最终得到的实际上是自定义控件。虽然它可能源自网格,但您通常不关心我决定如何创建布局...您只关心我给您一些具有UserName 和Password 属性的控件,您可以附加到还有一些可以执行的LoginCommand。正是这种固有的差异实际上使它成为了自定义视图。