[转] Silverlight Navigation(多页面切换、传值)
?
導(dǎo)航.簡(jiǎn)單的理解可以是從一個(gè)頁(yè)面跳轉(zhuǎn)到另外一個(gè)頁(yè)面。在傳統(tǒng)的ASP.NET網(wǎng)站中這種效果很容易實(shí)現(xiàn)。而在Silverlight中我們也同樣可以,我們有兩種方法來(lái)實(shí)現(xiàn)這個(gè)效果。
???第一個(gè)選擇是使用代碼更改頁(yè)面視圖(修改容器Content屬性),移除/添加User Control來(lái)實(shí)現(xiàn)導(dǎo)航,這個(gè)方法比較簡(jiǎn)單、直接代碼量也很少。并且在這個(gè)過(guò)程中還可以加入動(dòng)畫(huà)、變形等效果。
???第二個(gè)選擇就是使用Silverlight的導(dǎo)航系統(tǒng),導(dǎo)航系統(tǒng)包含兩個(gè)主要的控件:Frame、Page。基本的效果是可以在一個(gè)Frame里面切換多個(gè)頁(yè)面(UserControl、Page)。
?? 此次先簡(jiǎn)單介紹下第一種方法。?? 簡(jiǎn)單的頁(yè)面切換效果:
?? 這個(gè)例子,將頁(yè)面分成上下兩部分,上面表示菜單,下面放置一個(gè)容器空間用于承載內(nèi)容。容器控件你可以旋轉(zhuǎn)Border、ScrollViewer、StackPanel、Grid。下面是主頁(yè)面的代碼:
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
?? ??? <RowDefinition Height="*"></RowDefinition>
?? ??? <RowDefinition Height="Auto"></RowDefinition> ??
?? <RowDefinition Height="6*"></RowDefinition>
</Grid.RowDefinitions>??
<ListBox Grid.Row="0" SelectionChanged="lstPages_SelectionChanged">
?? ?? <!--頁(yè)面列表-->
</ListBox>
<basics:GridSplitter Grid.Row="1" Margin="0 3" HorizontalAlignment="Stretch"
?? ?? ??? Height="2"></basics:GridSplitter> ???
<Border Grid.Row="2" BorderBrush="SlateGray" BorderThickness="1"
?? ?? ??? x:Name="mainFrame" Background="AliceBlue"></Border>
</Grid>
這個(gè)例子中使用Border作為容器命名為mainFrame,在頁(yè)面加載的時(shí)候先為容器加入一個(gè)頁(yè)面(為項(xiàng)目添加2個(gè)以上UserControl):
Page1 page1 = new Page1();
mainFrame.Child = page1;
這里的容器控件是多選的,你也可使用單行單列的Grid。下面為L(zhǎng)istBox加入事件代碼:
private void lstPages_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
//獲取當(dāng)前的Item
string newPageName = ((ListBoxItem)e.AddedItems[0]).Content.ToString();
//根據(jù)名稱(chēng)使用反射創(chuàng)建一個(gè)UserControl實(shí)例
Type type = this.GetType();
Assembly assembly = type.Assembly;
UserControl newPage = (UserControl)assembly.CreateInstance(
type.Namespace + "." + newPageName);
//加入到容器中.
mainFrame.Child = newPage;
}
至此一個(gè)簡(jiǎn)單的頁(yè)面切換效果就OK了。
●使用根視圖(Root Visual)
上面是一個(gè)簡(jiǎn)單的例子,這個(gè)方法很常見(jiàn),但不是通用方式。它的小缺陷是整個(gè)頁(yè)面布局已經(jīng)固定死了,工具欄或頁(yè)面始終都固定在那里,那如果你想要的是一個(gè)全新的頁(yè)面就不行了。下面對(duì)這個(gè)小例子進(jìn)行一下擴(kuò)展就可以達(dá)到我們的目的了。
首先在App.xaml.cs中聲明一個(gè)Grid:
??? private Grid rootGrid = new Grid();
然后修改Appliaction_Startup事件代碼:
??? this.RootVisual = rootGrid;
??? rootGrid.Children.Add(new Page1());
這樣只能保證在初始化的時(shí)候會(huì)有一個(gè)頁(yè)面而不能導(dǎo)航,為此在App.xaml.cs代碼中加入一個(gè)靜態(tài)方法,代碼如下:
public static void Navigation(UserControl newPage)
{
//獲取當(dāng)前的Appliaction實(shí)例
App currentApp = (App)Application.Current;
//修改當(dāng)前顯示頁(yè)面內(nèi)容.
currentApp.rootGrid.Children.Clear();
currentApp.rootGrid.Children.Add(newPage);
}
這里要注意 方法的參數(shù)是UserControl。這樣在你的UserControl中即可添加如下的代碼(可以加到button事件中)進(jìn)行頁(yè)面切換了:
App.Navigation(new Page2());
new的對(duì)象是你的目標(biāo)頁(yè)面,不要寫(xiě)錯(cuò)了。就這幾句代碼又完成了咱們的目的!
●保存頁(yè)面狀態(tài)(Cache)
如果你想讓用戶在返回到歷史頁(yè)面的時(shí)候可以頁(yè)面的修改狀態(tài)比如用戶輸入的數(shù)據(jù)。首先對(duì)項(xiàng)目進(jìn)行一下小小的修改,添加一個(gè)名字叫Pages的enmu,用于保存頁(yè)面名稱(chēng)以便使用字符串產(chǎn)生不必要的問(wèn)題:
public enum Pages
{
Page1,
Page2
}
下一步是在App.cs代碼中加入一個(gè)泛型集合用于保存頁(yè)面:
private static Dictionary<Pages, UserControl> pageCache = new Dictionary<Pages, UserControl>();
其中Key是Pages枚舉,Value是UserControl。然后從新定義Naviagte方法:
public static void Navigation(Pages newPage)
{
App currentApp = (App)Application.Current;
if (!pageCache.ContainsKey(newPage))
{
?? ???//根據(jù)名稱(chēng)使用反射創(chuàng)建目標(biāo)頁(yè)面實(shí)例,并加入緩存
?? ???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]);
}
這樣在其他的UserControl中調(diào)用如下代碼就可以進(jìn)行切換了:
App.Navigation(Pages.Page2);
如果在頁(yè)面中放置一個(gè)文本框然后輸入值,跳轉(zhuǎn)到其他頁(yè)面再切換回來(lái)的話就會(huì)看到文本框的值依然存在,這是因?yàn)閁serControl被保存在內(nèi)存中了。
如果你進(jìn)行切換就會(huì)發(fā)現(xiàn)TextBox的值依然存在.這樣就實(shí)現(xiàn)了簡(jiǎn)單的緩存.
●頁(yè)面?zhèn)髦?#xff1a;
關(guān)于頁(yè)面?zhèn)髦滴覂H僅說(shuō)一下我的方式,當(dāng)讓網(wǎng)上也有其他的關(guān)于頁(yè)面之間傳值的方法。主要是使用獨(dú)立存儲(chǔ)的IsolatedStorageSettings對(duì)象,首先在UserControl中創(chuàng)建對(duì)象:
private IsolatedStorageSettings appSettings = IsolatedStorageSettings.ApplicationSettings;然后在Button事件中加入如下代碼,用于傳值:
if (!appSettings.Contains("Page2"))
?? appSettings.Add("Page2", "UserName");
OK了,在目標(biāo)頁(yè)面獲取值的方式就簡(jiǎn)單了.
if (appSettings.Contains("Page2"))
txbShowvalue.Text = "User Name: " + appSettings["Page2"].ToString();
需要注意的一點(diǎn)是這個(gè)獲取值的代碼不要寫(xiě)在頁(yè)面的構(gòu)造函數(shù)里面,有可能不會(huì)觸發(fā),原因是在上面對(duì)象已經(jīng)保存在內(nèi)存中了,但是會(huì)觸發(fā)Loaded事件,因此可以把代碼放到這個(gè)事件里面。
你也可以使用同樣的方式來(lái)給Page1傳值。OK..關(guān)于第一種頁(yè)面導(dǎo)航、傳值、簡(jiǎn)單緩存,就介紹完畢..
下篇著重說(shuō)下關(guān)于Silverlight Navigation System..
關(guān)于獨(dú)立存儲(chǔ)請(qǐng)參考:http://www.bbniu.com/forum/thread-366-1-1.html
?
?
?
此次主要說(shuō)一下如何使用Navigation System進(jìn)行導(dǎo)航。它包含了兩個(gè)重要的控件:Frame、Page。其中Frame控件是主要控件因?yàn)樗?fù)責(zé)導(dǎo)航以及顯示內(nèi)容。而Page空間是一個(gè)可選的控件,它可以使用普通的UserControl來(lái)代替,但兩者之間稍有差別,后面會(huì)簡(jiǎn)單說(shuō)一下。
1.Frame控件
Frame控件也是一個(gè)容器控件,它通過(guò)Content屬性進(jìn)行修改內(nèi)容,當(dāng)然最好是使用Navigate()方法來(lái)代替Content屬性,因?yàn)樗葧?huì)修改Content屬性也會(huì)觸發(fā)事件和保存Frame的日志(歷史記錄,更改當(dāng)前瀏覽器的地址)。下面看一個(gè)簡(jiǎn)單的例子,首先定義一個(gè)兩行一列的Grid,上面是一個(gè)包含了Frame的Border,下面是用來(lái)觸發(fā)導(dǎo)航的按鈕:
<UserControl x:Class="FramNavigation.MainPage"
?? xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
?? ?? xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
?? xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
?? ?? xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
?? xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
?? ?? mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<Grid x:Name="LayoutRoot"> ?? ???
<Grid> ?? ?? ??
?? ?? <Grid.RowDefinitions> ?? ?? ?? ??
?? ?? ?? <RowDefinition></RowDefinition> ?? ???
?? ?? ?? <RowDefinition Height="Auto"></RowDefinition> ?? ?? ??
?? ??? </Grid.RowDefinitions>
?? ??? <Border Margin="10" Padding="10" BorderBrush="DarkOrange"
?? ?? ?? ?? ?? ?? BorderThickness="2" CornerRadius="4"> ?? ?? ?? ??
?? ?? ?? ?? <navigation:Frame x:Name="mainFrame"></navigation:Frame>
?? ??? </Border> ?? ?? ??
?? ??? <Button Grid.Row="1" Margin="5" Padding="5" HorizontalAlignment="Center"
?? ?? ?? ?? ?? ???Content="Go to Page1" Click="btnNavigate_Click"></Button> ?? ???
</Grid>
</Grid>
</UserControl>
使Frame記得添加System.Windows.Controls.Navigation.dll引用。
然后在項(xiàng)目中創(chuàng)建一個(gè)UserControl命名為Page1,并在Main.xaml.cs的按鈕事件中加入如下代碼:
mainFrame.Navigate(new Uri("/Page1.xaml", UriKind.Relative));
Uri前的“/”表示應(yīng)用程序的根目錄..不可以使用Navigate()方法訪問(wèn)應(yīng)用程序以外的頁(yè)面,比如其他網(wǎng)站的頁(yè)面。同樣也可以使用如下代碼代替Navigate()方法:
mainFrame.Content = new Page1();
如果你觀察就會(huì)發(fā)現(xiàn)前后的瀏覽器地址欄是不一樣的,你也可以使用Frame.Source屬性查看當(dāng)前Uri.
這是因?yàn)橹恍薷腃ontent屬性不會(huì)觸發(fā)Navigation事件.
2.與瀏覽器集成
當(dāng)你使用Navigate()方法更新Frame控件內(nèi)容時(shí)那么目標(biāo)的xaml頁(yè)面就會(huì)以#隔開(kāi)附加到當(dāng)前的地址中,所以前后的地址就如上圖所示的,多出了#Page1.xaml部分。
這個(gè)特點(diǎn)即有好處也有潛在的危害。本來(lái)當(dāng)你使用Frame來(lái)創(chuàng)建導(dǎo)航系統(tǒng),每個(gè)頁(yè)面都會(huì)有一個(gè)獨(dú)立的名稱(chēng)標(biāo)識(shí),唯一的歷史記錄以及使用每次重新訪問(wèn)。比如當(dāng)你重新打開(kāi)瀏覽器在初始地址后面加入#Page1.xaml那么你就可以進(jìn)入到這個(gè)頁(yè)面,同樣你也可以把這個(gè)完整的地址加入到標(biāo)簽中以便下次訪問(wèn)。這個(gè)特性叫做Deep linking.因此使得Silverlight對(duì)搜索引擎是友好的。比如你可以創(chuàng)建多個(gè)HTML/ASP.NET頁(yè)面,然后讓他們指向同一個(gè)XAP,不過(guò)URI連接到不同的頁(yè)面,那么搜索引擎就會(huì)為你的程序創(chuàng)建多個(gè)索引(嘿嘿)。
這只是它的一個(gè)好處那么下面看問(wèn)題是什么:
- 如果一個(gè)頁(yè)面中存在多個(gè)Frame控件會(huì)怎么樣?
使用URI片段可以標(biāo)識(shí)一個(gè)頁(yè)面,但是真?zhèn)€URI中并沒(méi)有標(biāo)識(shí)Frmae,這說(shuō)明在程序中同事只有一個(gè)Frame控件在工作。(程序中包含多個(gè)Frame的做法很少見(jiàn))
但是如果不止一個(gè)Frame控件,它們將會(huì)同時(shí)相應(yīng)瀏覽器地址,如果你重寫(xiě)URI進(jìn)行訪問(wèn)或調(diào)用Navigate()方法那么請(qǐng)求的頁(yè)面就會(huì)添加到每一個(gè)Frame中。為了避免這種情況,你需要選擇一個(gè)Frame控件來(lái)做為主控件,這個(gè)控件會(huì)受到瀏覽器歷史地址的影響,而其他的Frame則會(huì)負(fù)責(zé)跟蹤自己的導(dǎo)航而不受瀏覽器影響。為了達(dá)到這個(gè)目的你需要為每一個(gè)副Frame的JournalOwnership 屬性設(shè)置為OwnJournal,這樣的話這些Frame就只能通過(guò)代碼調(diào)用Navigate方法進(jìn)行導(dǎo)航了。下面是JournalOwnership 屬性值的說(shuō)明(或看MSDN中更詳細(xì)的介紹): - 如果頁(yè)面中并不存在Frame控件會(huì)怎么樣?
使用URI訪問(wèn)多Frame的程序并不是唯一的問(wèn)題,還有一個(gè)問(wèn)題是是否能正確的處理用戶請(qǐng)求,因?yàn)橛锌赡躌oot visual中并不包含F(xiàn)rame。如果你用代碼動(dòng)態(tài)生成用戶界面。比如使用代碼創(chuàng)建Frame對(duì)象或者在進(jìn)入另外一個(gè)頁(yè)面的時(shí)候頁(yè)面中包含了一個(gè)Frame。這種情況下程序會(huì)正常運(yùn)行,不過(guò)因?yàn)闆](méi)有frame可用,URI片段會(huì)被忽略。
為了避免此類(lèi)問(wèn)題你可以簡(jiǎn)化應(yīng)用程序確保在啟動(dòng)的時(shí)候frame是可用的,并且在Application.Startup中驗(yàn)證請(qǐng)求的地址中是否含有URI片段,驗(yàn)證代碼如下:
string fragment = System.Windows.Browser.HtmlPage.Document.DocumentUri.Fragment;
3.安全問(wèn)題如何?
從另一個(gè)角度考慮,也給你的程序留了一個(gè)很多的后門(mén)。比如用戶輸入U(xiǎn)RI訪問(wèn)了一個(gè)你不想使用Navigate()方法訪問(wèn)的頁(yè)面。Silverlight本身并沒(méi)有提供措施來(lái)避免此類(lèi)問(wèn)題,因此在你使用導(dǎo)航系統(tǒng)的時(shí)候潛在的也給你帶來(lái)了URI訪問(wèn)的問(wèn)題。
不過(guò)幸好你可以使用以下方法來(lái)人為避免。第一個(gè)像前面一樣設(shè)置Frame的JournalOwnership為OwnJournal,那樣就可以避免使用URL訪問(wèn)你應(yīng)用程序的任何頁(yè)面,同時(shí)地址也不會(huì)集成到瀏覽器的歷史記錄列表中。另外一個(gè)更好的方法是使用Navigating事件,這個(gè)方法可以驗(yàn)證請(qǐng)求的URI從而有選擇性的進(jìn)行導(dǎo)航,驗(yàn)證代碼如下:
void mainFrame_Navigating(object sender, System.Windows.Navigation.NavigatingCancelEventArgs e)
{
if (e.Uri.ToString().ToLower().Contains("Page1.xaml")) {
?? e.Cancel = true; }
}
這樣就可以在程序執(zhí)行Navigate()方法后來(lái)驗(yàn)證URI是否合法。從而避免用戶訪問(wèn)到禁止請(qǐng)求的頁(yè)面。
4.對(duì)歷史記錄的支持
Frame控件的導(dǎo)航也可以與瀏覽器進(jìn)行集成。你每次調(diào)用Navigate()方法,Silverlight就會(huì)添加一個(gè)地址到瀏覽器的歷史記錄中(如下圖)。使用瀏覽器的前進(jìn)/后臺(tái)按鈕或者在歷史記錄列表中選擇一個(gè)頁(yè)面都可以正常的訪問(wèn)歷史頁(yè)面。你可以復(fù)制地址,然后重新打開(kāi)瀏覽器進(jìn)行訪問(wèn),依然是可以的。這樣Silverlgiht的Appliaction.Startup事件會(huì)重新觸發(fā),并加載相應(yīng)的頁(yè)面到Frame中。
如果你在按鈕事件中連續(xù)多次調(diào)用Navigate()方法那么頁(yè)面會(huì)加載你最后一個(gè)方法訪問(wèn)的頁(yè)面,不過(guò)其他頁(yè)面會(huì)加入瀏覽器的歷史記錄中。另外需要注意一下,如果你沒(méi)有使用UriMapper設(shè)置初始內(nèi)容,那么你點(diǎn)擊后臺(tái)按鈕回到初始頁(yè)面很有可能會(huì)產(chǎn)生一個(gè)錯(cuò)誤“No XAML found at the location”.
5.URI Mapping
正如我們看到的,頁(yè)面是以URI片段方式顯示在URI中的,那么你可能不想讓用戶看到具體的頁(yè)面名稱(chēng),并且也不希望.XAML結(jié)尾讓人感覺(jué)到混淆,而使用更簡(jiǎn)單、易記的名稱(chēng)。那么為了解決這個(gè)問(wèn)題可以使用URI Mapping來(lái)定義簡(jiǎn)單的URI片段。首先需要在資源中加入U(xiǎn)riMapper對(duì)象,一般是定義在App.xaml中的
<!--xmlns:navigation="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation"-->
<Application.Resources>
?? ?? <navigation:UriMapper x:Key="PageMapper">
?? ?? </navigation:UriMapper>
</Application.Resources>
同時(shí)在頁(yè)面Frame控件設(shè)置屬性UriMapper:
<navigation:Frame x:Name="mainFrame" UriMapper="{StaticResource PageMapper}"></navigation:Frame>
現(xiàn)在你就可以在UriMapper中添加映射了:
<navigation:UriMapping Uri="Home" MappedUri="/Page1.xaml" />
再次訪問(wèn)頁(yè)面然后看看地址欄結(jié)尾就會(huì)顯示成#Home,對(duì)了,記得修改導(dǎo)航按鈕的事件:
mainFrame.Navigate(new Uri("Home", UriKind.Relative));
否則地址欄是不會(huì)變化的。并且在映射地址前面不再需要加入一個(gè)“/”,它同樣能正常工作并且訪問(wèn)到目標(biāo)頁(yè)面。另外一個(gè)還可以設(shè)置一個(gè)頁(yè)面作為初始頁(yè)面。
<navigation:UriMapping Uri="" MappedUri="/InitialPage.xaml" />
那么這樣的話,當(dāng)你使用后臺(tái)按鈕回到首頁(yè)就不會(huì)再出現(xiàn)剛才說(shuō)的那個(gè)“No XAML found at the location”的錯(cuò)了。現(xiàn)在是強(qiáng)制的設(shè)置初始頁(yè)面,從某種意義上講也算是Silverlight的一個(gè)BUG。
URI地址映射是支持地址欄參數(shù),在說(shuō)Page控件的時(shí)候會(huì)再專(zhuān)門(mén)介紹一下..
<navigation:UriMapping Uri="Home/{name}" MappedUri="/Page1.xaml?name={name}" />
6.支持自定義 前進(jìn)/后退導(dǎo)航按鈕.
我們可以設(shè)置了Frame控件的JournalOwnership屬性來(lái)確定它如何與瀏覽器集成,管理日志。如果設(shè)置成OwnJournal那么Frame將自己來(lái)管理歷史記錄,不會(huì)與瀏覽器集成。這種情況就需要你自己來(lái)提供前進(jìn)/后退功能了,一般是使用兩個(gè)按鈕來(lái)代替前進(jìn)/后退。
而如果你的程序需要支持out-ofbrowser application,那么設(shè)置自定義的前進(jìn)后臺(tái)按鈕就很有比較了,因?yàn)樗沁\(yùn)行在普通的windws窗口中的,不會(huì)有瀏覽器的導(dǎo)航按鈕,那怕你并沒(méi)有設(shè)置JournalOwnership屬性,并且你可以判斷是否是OOB來(lái)顯示你的導(dǎo)航按鈕,你可以將以下代碼添加到程序中:
if (App.Current.IsRunningOutOfBrowser)
btnNavigate.Visibility = Visibility.Visible;
這樣就可以根據(jù)是否為OOB來(lái)控制按鈕了。并且自定義按鈕你也可以加你喜歡的樣式或動(dòng)畫(huà)效果,并且還可以根據(jù)Frame的兩個(gè)屬性來(lái)判斷當(dāng)前頁(yè)面是否是第一頁(yè)/最后一頁(yè)來(lái)禁用按鈕或修改按鈕樣式:
void mainFrame_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
?? ???if (mainFrame.CanGoBack)
?? ?? ?? btnBack.Visibility = Visibility.Collapsed;
?? ???else
?? ?? ?? btnBack.Visibility = Visibility.Visible;
?? ???if (mainFrame.CanGoForward)
?? ?? ?? btnForward.Visibility = Visibility.Collapsed;
?? ???else
?? ?? ?? btnForward.Visibility = Visibility.Visible;
}
這只是判斷按鈕顯示與否。你也可以修改按鈕視覺(jué)效果或禁用它們(比如更改顏色、透明度、圖片、添加動(dòng)畫(huà)),具體怎么做就看自己喜歡了。
7.HyperlinkButton
在前面我們是使用普通按鈕來(lái)觸發(fā)導(dǎo)航事件的。一般情況下Silverlight是使用HyperlinkButton來(lái)進(jìn)行導(dǎo)航的,這個(gè)按鈕使用起來(lái)相當(dāng)?shù)暮?jiǎn)單,只要設(shè)置按鈕的NavigateUri屬性指向頁(yè)面的URI或者是在UriMapper中配置的地址都行,代碼參考如下:
<StackPanel Margin="5" HorizontalAlignment="Center" Orientation="Horizontal"> ???
?? ?? ??? <HyperlinkButton NavigateUri="/Page1.xaml" Content="Page 1" Margin="3" /> ???
?? ?? ??? <HyperlinkButton NavigateUri="/Page2.xaml" Content="Page 2" Margin="3" /> ???
?? ?? ??? <HyperlinkButton NavigateUri="Home" Content="Home" Margin="3" />
</StackPanel>
OK…..限于篇幅,就主要說(shuō)這些.這次主要說(shuō)的是使用Frame來(lái)創(chuàng)建導(dǎo)航系統(tǒng)..由于個(gè)人水平問(wèn)題,如果什么地方有錯(cuò)誤的地方,還麻煩各位提出,我會(huì)及時(shí)改正..
下次注重說(shuō)一下關(guān)于使用Page來(lái)代替UserControl以及推薦幾個(gè)不錯(cuò)的Navigation Templates?
?
此次主要是接著Frame來(lái)說(shuō)的,主要是說(shuō)一下Page控件以及使用模版.
在之前的例子中使用的是UserControl來(lái)做為頁(yè)面,但通常的話我們是使用Page控件的,或者自己繼承Page類(lèi)來(lái)代替UserControl。因?yàn)镻age提供了更方便的導(dǎo)航功能以及狀態(tài)管理。其實(shí),Page類(lèi)是繼承自UserControl的,然后添加了一些成員,一些可重寫(xiě)的方法和四個(gè)屬性:Title、NavigationService、NavigationContext、NavigationCacheMode。其中Titel屬性比較簡(jiǎn)單,不做多說(shuō),其他屬性在后面都會(huì)有說(shuō)到。
使用Page控件很簡(jiǎn)單,和向項(xiàng)目中添加UserControl一樣。
1.Page控件屬性介紹
每一個(gè)Page控件內(nèi)都會(huì)有一個(gè)NavigationService屬性,這個(gè)屬性就相當(dāng)于訪問(wèn)Silverlight導(dǎo)航系統(tǒng)的入口,因?yàn)樗峁┝伺cFrame對(duì)象一樣的方法和屬性(Navigate()、GoBack()、GoForward(),屬性有CanGoBack、CanGoForward、CurrentSource等)。意思就是說(shuō)在Page里面就可以進(jìn)行導(dǎo)航了..
- this.NavigationService.Navigate(new Uri("/Page2.xaml", UriKind.Relative));
Page類(lèi)還含有一個(gè)NavigationContext屬性用來(lái)訪問(wèn)NavigationContext對(duì)象。使用這個(gè)屬性可以獲取當(dāng)前的URL,使用QueryString可以獲取URL中的參數(shù)。也就是說(shuō)你可以在跳轉(zhuǎn)頁(yè)面的時(shí)候使用地址欄參數(shù)傳值。如下:
- string uriText = String.Format("/Product.xaml?id={0}&type={1}",productID, productType);
- mainFrame.Navigate(new Uri(uriText), UriKind.Relative);
這樣你就可以傳兩個(gè)值到目標(biāo)頁(yè)面了 ..
然后在Priduct.xaml頁(yè)面你就可以獲取到值了:
- int productID, type;
- ?? ?? ?? if (this.NavigationContext.QueryString.ContainsKey("productID"))
- ?? ?? ?? ?? productID = Int32.Parse(this.NavigationContext.QueryString["productID"]);
- ?? ?? ?? if (this.NavigationContext.QueryString.ContainsKey("type"))
- ?? ?? ?? ?? type = Int32.Parse(this.NavigationContext.QueryString["type"]);
??? 當(dāng)讓你還可以使用其他方式傳值,比如在存儲(chǔ)在Appliaction對(duì)象中,或者是使用獨(dú)立存儲(chǔ)都可以實(shí)現(xiàn),因?yàn)槭褂肬RL參數(shù)很容易就會(huì)被篡改..
保存頁(yè)面狀態(tài)
通常,用戶第一次進(jìn)入頁(yè)面或者是使用前進(jìn)后退按鈕切換頁(yè)面,都會(huì)重新創(chuàng)建一個(gè)對(duì)象,當(dāng)用戶離開(kāi),對(duì)象就會(huì)被釋放。這種情況下,如果用戶輸入的有信息,再回到頁(yè)面就會(huì)編程默認(rèn)值,頁(yè)面的其他成員也會(huì)初始化成默認(rèn)值。而如果可以存儲(chǔ)頁(yè)面狀態(tài)的話就不會(huì)出現(xiàn)這種情況了。
Silverlight允許使用Page.NavigationCacheMode屬性來(lái)設(shè)置存儲(chǔ)策略,這個(gè)屬性的默認(rèn)值是Disabled所以不會(huì)默認(rèn)不會(huì)存儲(chǔ)頁(yè)面。把屬性設(shè)置為Required那么頁(yè)面就會(huì)保存到內(nèi)存中。當(dāng)用戶離開(kāi)頁(yè)面再返回的時(shí)候就可以看到自己修改的內(nèi)容依然存在,不過(guò)再次回到頁(yè)面不會(huì)觸發(fā)頁(yè)面的構(gòu)造方法,所以如果你在構(gòu)造函數(shù)里寫(xiě)的有邏輯就需要注意了。不過(guò)會(huì)觸發(fā)頁(yè)面的Loaded事件。
NavigationCacheMode的另外一個(gè)值是Enabled,如果設(shè)置成這個(gè)值,那么頁(yè)面就好與Frame.CacheSize(保存頁(yè)面的數(shù)量)屬性關(guān)聯(lián),加入CacheSize屬性設(shè)置為10,當(dāng)?shù)?1個(gè)頁(yè)面存儲(chǔ)進(jìn)來(lái)的話第一個(gè)頁(yè)面就會(huì)被釋放。而NavigationCacheMode屬性設(shè)置為Required屬性頁(yè)面就不會(huì)被計(jì)算在CacheSize中。這個(gè)可以根據(jù)自己的需要進(jìn)行選擇。
Page控件的方法
??? Page類(lèi)包含了幾個(gè)方法使你能更加靈活的管理導(dǎo)航。
- OnNavigatedTo():當(dāng)頁(yè)面不再是框架中的活動(dòng)頁(yè)面時(shí)調(diào)用。
- OnNavigatingFrom():當(dāng)頁(yè)面成為框架中的活動(dòng)頁(yè)面時(shí)調(diào)用。
- OnNavigatedFrom():在頁(yè)面即將不再是框架中的活動(dòng)頁(yè)面時(shí)調(diào)用。
你可以使用這些方法在離開(kāi)頁(yè)面或是訪問(wèn)頁(yè)面時(shí)添加一些自己的邏輯,比如初始化一些參數(shù)或是管理其他狀態(tài)。
?? 關(guān)于Page類(lèi)就說(shuō)到這里,詳細(xì)的用法與說(shuō)明可以查看MSDN..
Navigation Templates
現(xiàn)在已經(jīng)學(xué)會(huì)如何使用Frome/Page控件來(lái)創(chuàng)建具有導(dǎo)航功能的應(yīng)用程序,然后美中不足的是視覺(jué)效果還具有很多差距。不過(guò)你可以模擬別人的實(shí)例來(lái)不到完善,從而達(dá)到自己的效果。另外一個(gè)辦法是使用現(xiàn)有的模版。
如果你使用vs自帶的Silverlight Navigation Appliaction模版創(chuàng)建一個(gè)程序的話,會(huì)自動(dòng)給你創(chuàng)建一套默認(rèn)樣式。
??? 這個(gè)模版已經(jīng)可以滿足一些基本的需求:頁(yè)面的上方為導(dǎo)航按鈕,下方為內(nèi)容面板。這個(gè)是默認(rèn)模版,而Silverlight團(tuán)隊(duì)還提供了其他的幾個(gè)模版,在上一篇文章中已經(jīng)展示了效果圖,你可以在本文附件中下載。具體用法是替換Style.xaml文件就OK了..
轉(zhuǎn)載于:https://www.cnblogs.com/xixifusigao/archive/2010/01/19/1651709.html
總結(jié)
以上是生活随笔為你收集整理的[转] Silverlight Navigation(多页面切换、传值)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 多生孩子,图啥呢?
- 下一篇: 我的程序员偶像在哪里?