Shell 使用参数和 TabBar 进行路由
Shell Routing With Parameters And TabBar
我正在尝试将参数路由到可以被多个选项卡重复使用的页面(其中包含 WebView
)。我想传递 Url
和 Title
但到目前为止 BrowserPage
我得到的是空字符串
AppShell.xaml
<TabBar>
<ShellContent Title="Page 1" Icon="icon_about.png" Route="Page1Route" ContentTemplate="{DataTemplate local:BrowserPage}"/>
<ShellContent Title="Page 2" Icon="icon_about.png" Route="Page2Route" ContentTemplate="{DataTemplate local:BrowserPage}"/>
</TabBar>
AppShell.xaml.cs
public partial class AppShell : Xamarin.Forms.Shell {
public AppShell() {
InitializeComponent();
Routing.RegisterRoute("Page1Route?Url=page1url&Title=Page1", typeof(BrowserPage));
Routing.RegisterRoute("Page2Route?Url=page2url&Title=Page2", typeof(BrowserPage));
}
}
BrowserPage.xaml.cs
[XamlCompilation(XamlCompilationOptions.Compile)]
[QueryProperty(nameof(Url), nameof(Url))]
[QueryProperty(nameof(Title), nameof(Title))]
public partial class BrowserPage : ContentPage {
public BrowserPage() {
InitializeComponent();
((BrowserViewModel)BindingContext).Title = Title;
((BrowserViewModel)BindingContext).Url = Url;
}
private string url = "";
public string Url {
get {
return url;
}
set {
url = value;
OnPropertyChanged();
}
}
}
在 BrowserPage
代码隐藏中,Title
和 Url
为空。
如何以这种方式正确传递和接收数据?
路由注册带参数和不带参数都是一样的,参数在GoToAsync()
调用时发送(指定)而不是在RegisterRoute()
调用时发送(指定),所以导航到[=16时需要提供参数=].
public partial class AppShell : Xamarin.Forms.Shell {
public AppShell() {
InitializeComponent();
Routing.RegisterRoute(nameof(BrowserPage), typeof(BrowserPage));
}
}
Page1.xaml.cs
async void Button_Clicked(object sender, System.EventArgs e)
{
await Shell.Current.GoToAsync($"{nameof(BrowserPage)}?Title=Page1Title&Url=Page1Url");
}
Page2.xaml.cs
async void Button_Clicked(object sender, System.EventArgs e)
{
await Shell.Current.GoToAsync($"{nameof(BrowserPage)}?Title=Page2Title&Url=Page2Url");
}
此外,我相信您不需要 OnPropertyChanged
在自动 属性 后面的代码就足够了,Title
属性 未定义:
[QueryProperty(nameof(Url), nameof(Url))]
[QueryProperty(nameof(Title), nameof(Title))]
public partial class BrowserPage : ContentPage {
public BrowserPage() {
InitializeComponent();
((BrowserViewModel)BindingContext).Title = Title;
((BrowserViewModel)BindingContext).Url = Url;
}
public string Url { get; set; }
public string Title { get; set; }
}
编辑
在这种情况下,我建议您看看是否可以重新设计您的应用程序结构
首先,我们不在Routing.RegisterRoute
中添加传输数据。
如果注册页面,只需使用以下代码格式,不要添加传输数据。
Routing.RegisterRoute(nameof(Page1), typeof(Page1));
执行导航后,可以使用查询属性属性(QueryProperty
)传输数据。
比如我想导航到第1页,然后发送Title
和Url
。
private async void Button_Clicked(object sender, EventArgs e)
{
string Title = "myTitle";
string Url = "www.baidu.com";
await Shell.Current.GoToAsync($"Page1?title={Title}&url={Url}");
}
然后我们可以从Page1中获取值。
[XamlCompilation(XamlCompilationOptions.Compile)]
[QueryProperty(nameof(Title), "title")]
[QueryProperty(nameof(Url), "url")]
public partial class Page1 : ContentPage
{
private string url = "";
public string Url
{
get
{
return url;
}
set
{
url = value;
OnPropertyChanged("Url");
}
}
private string title = "";
public string Title
{
get
{
return title;
}
set
{
title = value;
OnPropertyChanged("Title");
}
}
public Page1()
{
InitializeComponent();
BindingContext = this;
}
}
}
这里是 运行 屏幕截图。
点击navi按钮,然后导航到page1
然后我们就可以得到值了
我能够通过完全删除路由并在 BrowserPage 的代码隐藏中添加 Url 属性 和标题 属性 来解决此问题:
private string url;
public string Url {
get => url;
set {
url = value;
((BrowserViewModel)BindingContext).SetSource(url);
}
}
private string pageTitle;
public string PageTitle {
get => pageTitle;
set {
pageTitle = value;
((BrowserViewModel)BindingContext).SetPageTitle(pageTitle);
}
}
在 AppShell.xaml 文件中,我删除了 Route
和 ContentTemplate
,并将 ShellContent.Content
设置为 described here。这允许我设置 url 和标题:
<ShellContent Title="Page 1" Icon="icon_about.png" >
<local:BrowserPage Url="http://www.yahoo.com" PageTitle="Page 1"/>
</ShellContent>
<ShellContent Title="Page 2" Icon="icon_about.png">
<local:BrowserPage Url="http://www.google.com" PageTitle="Page 2"/>
</ShellContent>
当应用程序启动并设置 Url 和 PageTitle 时,它会将其传递给 ViewModel 并加载页面。
所有需要实现此目标的人的完整代码。
BrowserPage.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:vm="clr-namespace:MyApp.ViewModels"
x:Class="MyApp.Views.BrowserPage"
Title="{Binding Title}">
<ContentPage.BindingContext>
<vm:BrowserViewModel/>
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<Color x:Key="Accent">#96d1ff</Color>
</ResourceDictionary>
</ContentPage.Resources>
<Grid>
<WebView
x:Name="mywebview"
Source="{Binding Source}"
Cookies="{Binding Cookies}"
Navigating="mywebview_Navigating"
Navigated="mywebview_Navigated"
WidthRequest="1000"
HeightRequest="1000"/>
<ActivityIndicator
x:Name="spinner"
Color="Black"
IsRunning="True"
HorizontalOptions="Center"
VerticalOptions="Center"/>
</Grid>
</ContentPage>
BrowserPage.xaml.cs
using MyApp.ViewModels;
using System.Diagnostics;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace MyApp.Views {
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class BrowserPage : ContentPage {
private string url;
public string Url {
get => url;
set {
url = value;
((BrowserViewModel)BindingContext).SetSource(url);
}
}
private string pageTitle;
public string PageTitle {
get => pageTitle;
set {
pageTitle = value;
((BrowserViewModel)BindingContext).SetPageTitle(pageTitle);
}
}
public BrowserPage() {
InitializeComponent();
}
private void mywebview_Navigated(object sender, WebNavigatedEventArgs e) {
mywebview.IsVisible = true;
spinner.IsVisible = false;
}
private void mywebview_Navigating(object sender, WebNavigatingEventArgs e) {
mywebview.IsVisible = false;
spinner.IsVisible = true;
}
}
}
BrowserViewModel.cs
using System;
using System.Net;
using Xamarin.Forms;
namespace MyApp.ViewModels {
public class BrowserViewModel : BaseViewModel {
private string text;
public string Text {
get => text;
set {
SetProperty(ref text, value);
}
}
private UrlWebViewSource source;
public UrlWebViewSource Source {
get {
return source;
}
set {
SetProperty(ref source, value);
}
}
private CookieContainer cookies;
public CookieContainer Cookies {
get {
return cookies;
}
set {
SetProperty(ref cookies, value);
}
}
public BrowserViewModel() { }
public BrowserViewModel(string title) {
Title = title;
}
public void SetPageTitle(string title) {
Title = title;
}
public void SetSource(string Url) {
CookieContainer cookieJar = new CookieContainer();
Uri uri = new Uri(Url, UriKind.RelativeOrAbsolute);
Cookie cookie = new Cookie {
...
};
cookieJar.Add(uri, cookie);
Cookies = cookieJar;
Source = new UrlWebViewSource { Url = uri.ToString() };
}
}
}
AppShell.xaml
<?xml version="1.0" encoding="UTF-8"?>
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MyApp.Views"
Title="MyApp"
x:Class="MyApp.AppShell">
<Shell.Resources>
<ResourceDictionary>
<Style x:Key="BaseStyle" TargetType="Element">
<Setter Property="Shell.BackgroundColor" Value="{StaticResource Primary}" />
<Setter Property="Shell.ForegroundColor" Value="White" />
<Setter Property="Shell.TitleColor" Value="White" />
<Setter Property="Shell.DisabledColor" Value="#B4FFFFFF" />
<Setter Property="Shell.UnselectedColor" Value="#95FFFFFF" />
<Setter Property="Shell.TabBarBackgroundColor" Value="{StaticResource Primary}" />
<Setter Property="Shell.TabBarForegroundColor" Value="White"/>
<Setter Property="Shell.TabBarUnselectedColor" Value="#95FFFFFF"/>
<Setter Property="Shell.TabBarTitleColor" Value="White"/>
</Style>
<Style TargetType="TabBar" BasedOn="{StaticResource BaseStyle}" />
<Style TargetType="FlyoutItem" BasedOn="{StaticResource BaseStyle}" />
</ResourceDictionary>
</Shell.Resources>
<TabBar>
<ShellContent Title="Page 1" Icon="icon_about.png" >
<local:BrowserPage Url="http://www.yahoo.com" PageTitle="Page 1"/>
</ShellContent>
<ShellContent Title="Page 2" Icon="icon_about.png">
<local:BrowserPage Url="http://www.google.com" PageTitle="Page 2"/>
</ShellContent>
</TabBar>
</Shell>
我正在尝试将参数路由到可以被多个选项卡重复使用的页面(其中包含 WebView
)。我想传递 Url
和 Title
但到目前为止 BrowserPage
我得到的是空字符串
AppShell.xaml
<TabBar>
<ShellContent Title="Page 1" Icon="icon_about.png" Route="Page1Route" ContentTemplate="{DataTemplate local:BrowserPage}"/>
<ShellContent Title="Page 2" Icon="icon_about.png" Route="Page2Route" ContentTemplate="{DataTemplate local:BrowserPage}"/>
</TabBar>
AppShell.xaml.cs
public partial class AppShell : Xamarin.Forms.Shell {
public AppShell() {
InitializeComponent();
Routing.RegisterRoute("Page1Route?Url=page1url&Title=Page1", typeof(BrowserPage));
Routing.RegisterRoute("Page2Route?Url=page2url&Title=Page2", typeof(BrowserPage));
}
}
BrowserPage.xaml.cs
[XamlCompilation(XamlCompilationOptions.Compile)]
[QueryProperty(nameof(Url), nameof(Url))]
[QueryProperty(nameof(Title), nameof(Title))]
public partial class BrowserPage : ContentPage {
public BrowserPage() {
InitializeComponent();
((BrowserViewModel)BindingContext).Title = Title;
((BrowserViewModel)BindingContext).Url = Url;
}
private string url = "";
public string Url {
get {
return url;
}
set {
url = value;
OnPropertyChanged();
}
}
}
在 BrowserPage
代码隐藏中,Title
和 Url
为空。
如何以这种方式正确传递和接收数据?
路由注册带参数和不带参数都是一样的,参数在GoToAsync()
调用时发送(指定)而不是在RegisterRoute()
调用时发送(指定),所以导航到[=16时需要提供参数=].
public partial class AppShell : Xamarin.Forms.Shell {
public AppShell() {
InitializeComponent();
Routing.RegisterRoute(nameof(BrowserPage), typeof(BrowserPage));
}
}
Page1.xaml.cs
async void Button_Clicked(object sender, System.EventArgs e)
{
await Shell.Current.GoToAsync($"{nameof(BrowserPage)}?Title=Page1Title&Url=Page1Url");
}
Page2.xaml.cs
async void Button_Clicked(object sender, System.EventArgs e)
{
await Shell.Current.GoToAsync($"{nameof(BrowserPage)}?Title=Page2Title&Url=Page2Url");
}
此外,我相信您不需要 OnPropertyChanged
在自动 属性 后面的代码就足够了,Title
属性 未定义:
[QueryProperty(nameof(Url), nameof(Url))]
[QueryProperty(nameof(Title), nameof(Title))]
public partial class BrowserPage : ContentPage {
public BrowserPage() {
InitializeComponent();
((BrowserViewModel)BindingContext).Title = Title;
((BrowserViewModel)BindingContext).Url = Url;
}
public string Url { get; set; }
public string Title { get; set; }
}
编辑
在这种情况下,我建议您看看是否可以重新设计您的应用程序结构
首先,我们不在Routing.RegisterRoute
中添加传输数据。
如果注册页面,只需使用以下代码格式,不要添加传输数据。
Routing.RegisterRoute(nameof(Page1), typeof(Page1));
执行导航后,可以使用查询属性属性(QueryProperty
)传输数据。
比如我想导航到第1页,然后发送Title
和Url
。
private async void Button_Clicked(object sender, EventArgs e)
{
string Title = "myTitle";
string Url = "www.baidu.com";
await Shell.Current.GoToAsync($"Page1?title={Title}&url={Url}");
}
然后我们可以从Page1中获取值。
[XamlCompilation(XamlCompilationOptions.Compile)]
[QueryProperty(nameof(Title), "title")]
[QueryProperty(nameof(Url), "url")]
public partial class Page1 : ContentPage
{
private string url = "";
public string Url
{
get
{
return url;
}
set
{
url = value;
OnPropertyChanged("Url");
}
}
private string title = "";
public string Title
{
get
{
return title;
}
set
{
title = value;
OnPropertyChanged("Title");
}
}
public Page1()
{
InitializeComponent();
BindingContext = this;
}
}
}
这里是 运行 屏幕截图。
点击navi按钮,然后导航到page1
然后我们就可以得到值了
我能够通过完全删除路由并在 BrowserPage 的代码隐藏中添加 Url 属性 和标题 属性 来解决此问题:
private string url;
public string Url {
get => url;
set {
url = value;
((BrowserViewModel)BindingContext).SetSource(url);
}
}
private string pageTitle;
public string PageTitle {
get => pageTitle;
set {
pageTitle = value;
((BrowserViewModel)BindingContext).SetPageTitle(pageTitle);
}
}
在 AppShell.xaml 文件中,我删除了 Route
和 ContentTemplate
,并将 ShellContent.Content
设置为 described here。这允许我设置 url 和标题:
<ShellContent Title="Page 1" Icon="icon_about.png" >
<local:BrowserPage Url="http://www.yahoo.com" PageTitle="Page 1"/>
</ShellContent>
<ShellContent Title="Page 2" Icon="icon_about.png">
<local:BrowserPage Url="http://www.google.com" PageTitle="Page 2"/>
</ShellContent>
当应用程序启动并设置 Url 和 PageTitle 时,它会将其传递给 ViewModel 并加载页面。
所有需要实现此目标的人的完整代码。
BrowserPage.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:vm="clr-namespace:MyApp.ViewModels"
x:Class="MyApp.Views.BrowserPage"
Title="{Binding Title}">
<ContentPage.BindingContext>
<vm:BrowserViewModel/>
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<Color x:Key="Accent">#96d1ff</Color>
</ResourceDictionary>
</ContentPage.Resources>
<Grid>
<WebView
x:Name="mywebview"
Source="{Binding Source}"
Cookies="{Binding Cookies}"
Navigating="mywebview_Navigating"
Navigated="mywebview_Navigated"
WidthRequest="1000"
HeightRequest="1000"/>
<ActivityIndicator
x:Name="spinner"
Color="Black"
IsRunning="True"
HorizontalOptions="Center"
VerticalOptions="Center"/>
</Grid>
</ContentPage>
BrowserPage.xaml.cs
using MyApp.ViewModels;
using System.Diagnostics;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace MyApp.Views {
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class BrowserPage : ContentPage {
private string url;
public string Url {
get => url;
set {
url = value;
((BrowserViewModel)BindingContext).SetSource(url);
}
}
private string pageTitle;
public string PageTitle {
get => pageTitle;
set {
pageTitle = value;
((BrowserViewModel)BindingContext).SetPageTitle(pageTitle);
}
}
public BrowserPage() {
InitializeComponent();
}
private void mywebview_Navigated(object sender, WebNavigatedEventArgs e) {
mywebview.IsVisible = true;
spinner.IsVisible = false;
}
private void mywebview_Navigating(object sender, WebNavigatingEventArgs e) {
mywebview.IsVisible = false;
spinner.IsVisible = true;
}
}
}
BrowserViewModel.cs
using System;
using System.Net;
using Xamarin.Forms;
namespace MyApp.ViewModels {
public class BrowserViewModel : BaseViewModel {
private string text;
public string Text {
get => text;
set {
SetProperty(ref text, value);
}
}
private UrlWebViewSource source;
public UrlWebViewSource Source {
get {
return source;
}
set {
SetProperty(ref source, value);
}
}
private CookieContainer cookies;
public CookieContainer Cookies {
get {
return cookies;
}
set {
SetProperty(ref cookies, value);
}
}
public BrowserViewModel() { }
public BrowserViewModel(string title) {
Title = title;
}
public void SetPageTitle(string title) {
Title = title;
}
public void SetSource(string Url) {
CookieContainer cookieJar = new CookieContainer();
Uri uri = new Uri(Url, UriKind.RelativeOrAbsolute);
Cookie cookie = new Cookie {
...
};
cookieJar.Add(uri, cookie);
Cookies = cookieJar;
Source = new UrlWebViewSource { Url = uri.ToString() };
}
}
}
AppShell.xaml
<?xml version="1.0" encoding="UTF-8"?>
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MyApp.Views"
Title="MyApp"
x:Class="MyApp.AppShell">
<Shell.Resources>
<ResourceDictionary>
<Style x:Key="BaseStyle" TargetType="Element">
<Setter Property="Shell.BackgroundColor" Value="{StaticResource Primary}" />
<Setter Property="Shell.ForegroundColor" Value="White" />
<Setter Property="Shell.TitleColor" Value="White" />
<Setter Property="Shell.DisabledColor" Value="#B4FFFFFF" />
<Setter Property="Shell.UnselectedColor" Value="#95FFFFFF" />
<Setter Property="Shell.TabBarBackgroundColor" Value="{StaticResource Primary}" />
<Setter Property="Shell.TabBarForegroundColor" Value="White"/>
<Setter Property="Shell.TabBarUnselectedColor" Value="#95FFFFFF"/>
<Setter Property="Shell.TabBarTitleColor" Value="White"/>
</Style>
<Style TargetType="TabBar" BasedOn="{StaticResource BaseStyle}" />
<Style TargetType="FlyoutItem" BasedOn="{StaticResource BaseStyle}" />
</ResourceDictionary>
</Shell.Resources>
<TabBar>
<ShellContent Title="Page 1" Icon="icon_about.png" >
<local:BrowserPage Url="http://www.yahoo.com" PageTitle="Page 1"/>
</ShellContent>
<ShellContent Title="Page 2" Icon="icon_about.png">
<local:BrowserPage Url="http://www.google.com" PageTitle="Page 2"/>
</ShellContent>
</TabBar>
</Shell>