多页面切换、传值(1)
导航.简单的理解可以是从一个页面跳转到另外一个页面。在传统的ASP.NET网站中这种效果很容易实现。而在Silverlight中我们也同样可以,我们有两种方法来实现这个效果。
A使用代码更改页面视图(修改容器Content属性),移除/添加User Control来实现导航,这个方法比较简单、直接代码量也很少。并且在这个过程中还可以加入动画、变形等效果。
B是使用Silverlight的导航系统,导航系统包含两个主要的控件:Frame、Page。基本的效果是可以在一个Frame里面切换多个页面(UserControl、Page)。
先简单介绍下第一种方法。 简单的页面切换效果:
这个例子,将页面分成上下两部分,上面表示菜单,下面放置一个容器空间用于承载内容。容器控件你可以旋转Border、ScrollViewer、StackPanel、Grid。下面是主页面的代码:
<Grid x:Name="LayoutRoot"> <Grid.RowDefinitions> <RowDefinition Height="*"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="6*"></RowDefinition> </Grid.RowDefinitions> <ListBox Grid.Row="1" Margin="0 3" Name="lst01" SelectionChanged="ListBox_SelectionChanged"> <ListBoxItem Content="页面1" /> <ListBoxItem Content="页面2" /> </ListBox> <Border Grid.Row="2" BorderBrush="SlateGray" BorderThickness="1" x:Name="mainFrame" Background="AliceBlue"></Border> </Grid>
这个例子中使用Border作为容器命名为mainFrame。
请事先在项目中添加两个用户控件,名称分别为Ctrl1和Ctrl2.
下面为ListBox加入事件代码:
private void lstPages_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (lst01.SelectedIndex == 0) { Ctrl1 ctrl11 = new Ctrl1(); mainFrame.Child = ctrl11; } else { Ctrl2 ctrl21 = new Ctrl2(); mainFrame.Child = ctrl21; }
}
至此一个简单的页面切换效果就OK了。这个DEMO的效果图如下:
●使用根视图(Root Visual)
上面是一个简单的例子,这个方法很常见,但不是通用方式。它的小缺陷是整个页面布局已经固定死了,工具栏或页面始终都固定在那里,那如果你想要的是一个全新的页面就不行了。下面对这个小例子进行一下扩展就可以达到我们的目的了。
在项目中首先添加两个页面,名称为Nav01和Nav02,用来对这两个页面互相切换和传值。
首先在App.xaml.cs中声明一个Grid:
private Grid rootGrid = new Grid();
然后修改Appliaction_Startup事件代码:
this.RootVisual = rootGrid;
rootGrid.Children.Add(new Nav01());
这样只能保证在初始化的时候会有一个页面而不能导航,为此在App.xaml.cs代码中加入一个静态方法,代码如下:
public static void Navigation(Page newPage)
{
//获取当前的Appliaction实例
App currentApp = (App)Application.Current;
//修改当前显示页面内容.
currentApp.rootGrid.Children.Clear();
currentApp.rootGrid.Children.Add(newPage);
}
这里要注意 方法的参数是Page。这样在你的Page中即可添加如下的代码(可以加到button事件中)进行页面切换了:
App.Navigation(new Nav02());
●保存页面状态(Cache)
如果你想让用户在返回到历史页面的时候可以页面的修改状态比如用户输入的数据。首先对项目进行一下小小的修改,添加一个名字叫Pages的enmu,用于保存页面名称以便使用字符串产生不必要的问题:
public enum Pages
{
Nav01,
Nav02
}
下一步是在App.cs代码中加入一个泛型集合用于保存页面:
private static Dictionary<Pages, Page> pageCache = new Dictionary<Pages, Page>();
其中Key是Pages枚举,Value是UserControl。然后从新定义Naviagte方法:
public static void Navigation(Pages newPage)
{
App currentApp = (App)Application.Current;
if (!pageCache.ContainsKey(newPage))
{
//根据名称使用反射创建目标页面实例,并加入缓存
Type type = currentApp.GetType();
Assembly assembly = type.Assembly;
pageCache[newPage] = (UserControl)assembly.CreateInstance(
type.Namespace + "." + newPage.ToString());
}
currentApp.rootGrid.Children.Clear();
currentApp.rootGrid.Children.Add(pageCache[newPage]);
}
这样在其他的Page中调用如下代码就可以进行切换了:
App.Navigation(Pages.Nav02); //从页面1切换至页面2
App.Navigation(Pages.Nav01); //从页面2切换至页面1
如果在页面中放置一个文本框然后输入值,跳转到其他页面再切换回来的话就会看到文本框的值依然存在,这是因为UserControl被保存在内存中了。效果图如下:
如果你进行切换就会发现TextBox的值依然存在.这样就实现了简单的缓存.
●页面传值:
关于页面传值我仅仅说一下我的方式,当让网上也有其他的关于页面之间传值的方法。主要是使用独立存储的IsolatedStorageSettings对象,首先在page中创建对象:
private IsolatedStorageSettings appSettings = IsolatedStorageSettings.ApplicationSettings;
然后在Button事件中加入如下代码,用于传值:
if (!appSettings.Contains("Nav02"))
appSettings.Add("Nav02", "UserName");
OK了,在目标页面获取值的方式就简单了.
if (appSettings.Contains("Nav02"))
txbShowvalue.Text = "User Name: " + appSettings["Nav02"].ToString();
需要注意的一点是这个获取值的代码不要写在页面的构造函数里面,有可能不会触发,原因是在上面对象已经保存在内存中了,但是会触发Loaded事件,因此可以把代码放到这个事件里面。最总效果如下:
你也可以使用同样的方式来给Page1传值。