Xamarin.Forms+Prism导航目标控件

Xamarin.Forms+Prism Navigation target control

我有一个由多种页面类型组成的 Xamarin 应用程序。我正在使用棱镜。

我希望应用程序的导航目标是主页面内应用程序中的嵌套视图,而不是主页面本身,这样 MainPage 就可以用作外部框架那里,一个嵌套的页面托管应用程序的导航服务。
通过这种方式,我可以让一些控件(即 back/forward/home)始终存在。 如何将 NavigationService's 'MainPage' 配置为实际 MainPage?
中的嵌套页面 我是 XF 的新手,之前没有使用过 NavigationPage,但它在这里有什么用吗?

我有一种方法。不完全是你想要的,但可以给你深思。您可以使用 SomeContent 属性:

创建 SomeBaseContentPage
public View SomeContent
{
  set
  {
    someGrid.Children.Add(value);
  }
}

然后从SomeBaseContentPage导出你的SomeContentPageA并在XAML中将你的具体内容放入属性<SomeBaseContentPage.SomeContent>.

你不知道。 Prism 的导航服务将不支持您尝试执行的操作,因为 INavigationService 是基于 Page 的。听起来你的方法很不正统。为什么不直接使用 NavigationPage 并在自定义渲染器中或作为工具栏项提供您的选项?

Prism 的 INavigationService 并不是为满足您的需求而设计的。幸运的是自定义视图!您可以按照之前的建议进行操作,但我通常会避免创建自定义页面,而是创建一个拥有自己内容的自定义视图 属性.

编辑:

Xamarin Forms 的术语可能会特别令人困惑,特别是如果您是 MVVM 和 Xamarin Forms 的新手,and/or 已经不再在其他平台上开发。

Xamarin Forms 称为 View 的内容在其他平台上通常称为 Control。这在使用 MVVM 框架(如 Prism)时尤其令人困惑,因为我们的 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,他们会转到下一个字段,或者它会调用按钮单击,但这仍然不会使它成为自定义页面。

有关 "Custom Page" 的示例,您可以查看 XLabs ExtendedTabbedPage. One thing you'll notice is there there are several new properties on their version of the TabbedPage. Of course their page only works because of the 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 实际上是一个自定义控件。虽然它可能是从网格派生的,但您通常不关心我如何决定创建布局...您只关心我给您一些具有 UserNamePassword 属性的控件你可以附加到一些可以执行的LoginCommand。事实上,正是这种内在差异使其成为自定义视图。