制作导航菜单
如果您的应用程序包含各种不同但在架构上相同的页面,所有这些页面都可以从主页导航,那么您可能有兴趣构建有时称为导航菜单的页面。 这是一个菜单,其中每个条目都是特定的页面类型。
ViewGalleryType程序旨在演示Xamarin.Forms中的所有View类。 它包含一个主页和一个页面,用于Xamarin.Forms中的每个可实例化类,它们来自View而不是Layout,但Map和OpenGLView除外。 这是18个类和18个ContentPage衍生产品,加上主页。 (项目名称上的类型后缀的原因很快就会显现出来。)
这18个页面类都存储在Portable Class Library中名为ViewPages的文件夹中。 这是一个例子:SliderPage.xaml。 它只是一个标签绑定到Value属性的Slider:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ViewGalleryType.SliderPage"
Title="Slider">
<StackLayout Padding="10, 0">
<Slider x:Name="slider"
VerticalOptions="CenterAndExpand" />
<Label Text="{Binding Source={x:Reference slider},
Path=Value,
StringFormat='The Slider value is {0}'}"
VerticalOptions="CenterAndExpand"
HorizontalAlignment="Center" />
</StackLayout>
</ContentPage>
其他17个是相似的。 有些页面在代码隐藏文件中有一些代码,但大多数只是调用InitializeComponent。
此外,ViewGalleryType项目有一个名为Images的文件夹,其中包含18个位图,每个View衍生的名称都延伸到几乎填满位图的表面。 这些位图由Windows Presentation Foundation程序生成,并在项目中标记为EmbeddedResource。 该项目还包含第13章“嵌入式资源”一节中描述的ImageResourceExtension类,以引用XAML文件中的位图。
主页名为ViewGalleryTypePage。 它在表的六个不同部分组装了18个ImageCell元素:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ViewGalleryType;assembly=ViewGalleryType"
x:Class="ViewGalleryType.ViewGalleryTypePage"
Title="View Gallery">
<TableView Intent="Menu">
<TableRoot>
<TableSection Title="Presentation Views">
<ImageCell ImageSource="{local:ImageResource ViewGalleryType.Images.Label.png}"
Text="Display text"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:LabelPage}" />
<ImageCell ImageSource="{local:ImageResource ViewGalleryType.Images.Image.png}"
Text="Display a bitmap"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:ImagePage}" />
<ImageCell ImageSource=
"{local:ImageResource ViewGalleryType.Images.BoxView.png}"
Text="Display a block"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:BoxViewPage}" />
<ImageCell ImageSource=
"{local:ImageResource ViewGalleryType.Images.WebView.png}"
Text="Display a web site"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:WebViewPage}" />
</TableSection>
<TableSection Title="Command Views">
<ImageCell ImageSource="{local:ImageResource ViewGalleryType.Images.Button.png}"
Text="Initiate a command"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:ButtonPage}" />
<ImageCell ImageSource=
"{local:ImageResource ViewGalleryType.Images.SearchBar.png}"
Text="Initiate a text search"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:SearchBarPage}" />
</TableSection>
<TableSection Title="Data-Type Views">
<ImageCell ImageSource="{local:ImageResource ViewGalleryType.Images.Slider.png}"
Text="Range of doubles"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:SliderPage}" />
<ImageCell ImageSource=
"{local:ImageResource ViewGalleryType.Images.Stepper.png}"
Text="Discrete doubles"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:StepperPage}" />
<ImageCell ImageSource="{local:ImageResource ViewGalleryType.Images.Switch.png}"
Text="Select true or false"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:SwitchPage}" />
<ImageCell ImageSource=
"{local:ImageResource ViewGalleryType.Images.DatePicker.png}"
Text="Select a date"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:DatePickerPage}" />
<ImageCell ImageSource=
"{local:ImageResource ViewGalleryType.Images.TimePicker.png}"
Text="Select a time"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:TimePickerPage}" />
</TableSection>
<TableSection Title="Text-Editing Views">
<ImageCell ImageSource="{local:ImageResource ViewGalleryType.Images.Entry.png}"
Text="Edit a single line"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:EntryPage}" />
<ImageCell ImageSource="{local:ImageResource ViewGalleryType.Images.Editor.png}"
Text="Edit a paragraph"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:EditorPage}" />
</TableSection>
<TableSection Title="Activity Indicator Views">
<ImageCell ImageSource=
"{local:ImageResource ViewGalleryType.Images.ActivityIndicator.png}"
Text="Show activity"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:ActivityIndicatorPage}" />
<ImageCell ImageSource=
"{local:ImageResource ViewGalleryType.Images.ProgressBar.png}"
Text="Show progress"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:ProgressBarPage}" />
</TableSection>
<TableSection Title="Collection Views">
<ImageCell ImageSource="{local:ImageResource ViewGalleryType.Images.Picker.png}"
Text="Pick item from list"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:PickerPage}" />
<ImageCell ImageSource=
"{local:ImageResource ViewGalleryType.Images.ListView.png}"
Text="Show a collection"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:ListViewPage}" />
<ImageCell ImageSource=
"{local:ImageResource ViewGalleryType.Images.TableView.png}"
Text="Show form or menu"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:TableViewPage}" />
</TableSection>
</TableRoot>
</TableView>
</ContentPage>
每个ImageCell都引用一个指示视图名称的位图和一个简要描述视图的Text属性。 ImageCell的Command属性绑定到ICommand对象
在代码隐藏文件中实现,CommandParameter是一个引用其中一个页面类的x:Type标记扩展。 您可能还记得,x:Type标记扩展是C#typeof运算符的XAML等效项,并且每个CommandParameter都是Type类型。
以下是三个平台上主页的外观:
代码隐藏文件定义每个ImageCell在绑定中引用的NavigateCommand属性。 Execute方法实现为lambda函数:它将Type参数(从XAML文件中的CommandParameter设置)传递给Activator.CreateInstance以实例化页面,然后导航到该页面:
public partial class ViewGalleryTypePage : ContentPage
{
public ViewGalleryTypePage()
{
InitializeComponent();
NavigateCommand = new Command<Type>(async (Type pageType) =>
{
Page page = (Page)Activator.CreateInstance(pageType);
await Navigation.PushAsync(page);
});
BindingContext = this;
}
public ICommand NavigateCommand { private set; get; }
}
构造函数通过将其BindingContext属性设置为自身来结束,因此XAML文件中的每个ImageCell都可以通过简单的Binding引用NavigateCommand属性。
点击Slider条目(例如)导航到SliderPage:
返回主页需要使用iOS和Android屏幕上的导航栏或Android和Windows 10 Mobile屏幕上的后退按钮。
每次导航到该页面时都会创建每个页面的新实例,因此SliderPage的这些不同实例当然不会保留您之前设置的Slider的值。
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ViewGalleryInst;assembly=ViewGalleryInst"
x:Class="ViewGalleryInst.ViewGalleryInstPage"
Title="View Gallery">
<TableView Intent="Menu">
<TableRoot>
<TableSection Title="Presentation Views">
<ImageCell ImageSource="{local:ImageResource ViewGalleryInst.Images.Label.png}"
Text="Display text"
Command="{Binding NavigateCommand}">
<ImageCell.CommandParameter>
<local:LabelPage />
</ImageCell.CommandParameter>
</ImageCell>
__
<ImageCell ImageSource=
"{local:ImageResource ViewGalleryInst.Images.TableView.png}"
Text="Show form or menu"
Command="{Binding NavigateCommand}">
<ImageCell.CommandParameter>
<local:TableViewPage />
</ImageCell.CommandParameter>
</ImageCell>
</TableSection>
</TableRoot>
</TableView>
</ContentPage>
现在,当您在SliderPage上操作Slider,然后返回到home并再次导航到SliderPage时,Slider将是相同的,因为它是相同的页面实例。
请记住,使用此配置,程序启动时总共会实例化19个页面类,这意味着将解析19个XAML文件,这可能会影响启动性能,并占用大量内存。
此外,在此运行时解析期间找到的XAML文件中的任何错误也将在程序启动时显现。 可能很难准确发现哪个XAML文件存在问题! 在构建一次性实例化多个页面类的程序时,您需要以增量方式添加新类,以确保在继续之前一切正常。
更好的是,完全避免这种技术。 根据需要实例化每个页面,并使用ViewModel保留与页面关联的数据。