WPF之Page介紹(以及Page之間的鏈接)


WPF中的Page相比Window來說更加的精簡,因為他沒有提供一個Show或者是Hide的方法,而是通過鏈接的方式進行頁面切換。此外,一般來說Page不設置自身的大小,因為頁面的尺寸由包含它的宿主窗體來決定的。如果設置了頁面的Width和Height大小,如果宿主的大小小於頁面的,則頁面會被裁剪;如果宿主的大小大於頁面的,則頁面會居中顯示。同時頁面可以設置WindowWidth和WindowHeight以及WindowTitle來設置宿主的寬度、高度、標題屬性。
先看個例子:

            NavigationWindow win = new NavigationWindow();
            //未設置大小
            //win.Content = new Page1();
            //宿主大小大於Page尺寸
            //win.Content = new Page1(300,300,500,500);
            //宿主大小小於Page尺寸
            win.Content = new Page1(500, 500, 300, 300);
            win.Show();

例子中設置了三種不同情況下頁面和宿主窗體之間的大小關系,看到的三種情況如下
三張圖片分別為,未對窗體進行大小設置,宿主大於頁面,宿主小於頁面.


下面介紹下Page頁面的宿主問題:
Page的宿主包括瀏覽器,導航窗口(NavigationWindow)和Frame,上例子中已經使用了NavigationWindow。后兩種均為WPF提供的Page宿主窗口,提供了從一個Page導航到另一個Page的功能,同時可以記錄歷史導航,以及一系列的導航事件。其中NavigationWindow繼承自Window,所以在外觀上與普通的窗口最大的區別是多了一個導航工具欄,不過可以通過設置ShowsNavigationUI屬性控制是否顯示。
NavigationWindow為頂級窗口,不允許嵌入到其他的元素中。而Frame則為輕量級,可以嵌入到其他元素中,如NavigationWindow或者Page,甚至Frame的嵌套。Frame默認沒有導航欄,可以設置NavigationUIVisibility屬性為Visible使其顯示。


例子,如下例子在NavigationWindow中放置了一個Page,然后在Page中嵌套了一個Frame:

<Page x:Class="WpfApplication4.Page1"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"
    Title="Page1">
    <Border BorderBrush="Red" BorderThickness="2" Margin="2">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition></RowDefinition>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <TextBlock Grid.Row="0" Text="該頁面的宿主窗口是一個NavigationWindow"
                        HorizontalAlignment="Center" VerticalAlignment="Center"  ></TextBlock>
            <Frame Source="Page2.xaml" NavigationUIVisibility="Visible" Grid.Row="1"></Frame>
        </Grid>
    </Border>
</Page>

同時設置App中的StartUrl為Page,效果如下:

可以看到,最外層是擁有導航的NavigationWindow,而內層還嵌套一個擁有導航的Frame.
細心的童鞋會發現,在上例子中我們並沒有添加NavigationWindow的代碼,可為什么還是有了效果呢?這是因為當設置了StartUri的對象為Page而不是Window,WPF就會為該Page創建一個NavigationWindow。

 

下面開始介紹Page之間的導航鏈接:
1.超鏈接(HyperLink)

 <Hyperlink  Click="Hyperlink_Click_1">開始閱讀路由事件</Hyperlink>
 <Hyperlink NavigateUri="Page4.xaml">開始閱讀路由事件</Hyperlink>
  private void Hyperlink_Click_1(object sender, RoutedEventArgs e)
        {
            NavigationService.Navigate(new Uri("pack://application:,,,/Page4.xaml"));
        }

上述代碼使用了HyperLink的兩種方式進行導航,一種是設置NavigateUri屬性為目標頁,另一種是使用NavigationService類的Navigate方法來進行導航頁(當然,此方法不限於
HyperLink使用).
除了上述比較簡單的使用外,HyperLink還可以在元素之間進行導航,例子如下:

<Page x:Class="WpfApplication4.Page4"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"
    Title="Page4">

    <Grid>
        <FlowDocumentReader>
            <FlowDocument>
                <Paragraph x:Name="para" FontSize="24" Background="AliceBlue">
                    <Figure Width="100" Height="100"  HorizontalAnchor="ColumnRight" HorizontalOffset="-10" VerticalAnchor="ParagraphTop" VerticalOffset="-30">
                        <BlockUIContainer>
                            <Image Source="bee.png"/>
                        </BlockUIContainer>
                    </Figure>
                    路由事件(Routed Event)
                </Paragraph>
                <Section FontFamily="華文仿宋">

                    <Paragraph>
                        黃蓉凝目看去,只見那兩只玉蜂雙翅上也都有字,那六個字也是一模一樣,右翅是“情谷底”,左翅是“我在絕”。黃蓉大奇,暗想:“造物雖奇,也決造不出這樣一批蜜蜂來之理。其中必有緣故。” ……
                    </Paragraph>
                    <Paragraph>
                        黃蓉不答,只是輕輕念着:“情谷底,我在絕。情谷底,我在絕。”她念了幾遍,隨即省悟:“啊!那是‘我在絕情谷底’。是誰在絕情谷底啊?難道是襄兒?”心中怦怦亂跳……
                    </Paragraph>
                    <Paragraph TextAlignment="Right">
                        ——《神雕俠侶:第三十八回 生死茫茫》
                    </Paragraph>
                </Section>
                <Section LineHeight="25" FontSize="15">
                    <Paragraph >
                        這一段講的是小龍女深陷絕情谷地,用花樹上的細刺,在玉蜂翅上刺下‘我在絕情谷底’六字,盼望玉蜂飛上之后,能為人發現。結果蜂翅上的細字被周伯通發現,而給黃蓉隱約猜到了其中含義。本節內容包括:
                    </Paragraph>
                    <List >
                        <ListItem>
                            <Paragraph>
                                <Hyperlink NavigateUri="Page4.xaml#first">
                                    <!--<Hyperlink Click="Hyperlink_Click">-->
                                    從玉蜂說起,回顧.Net事件模型
                                </Hyperlink>
                            </Paragraph>
                        </ListItem>
                        <ListItem>
                            <Paragraph>
                                <Hyperlink NavigateUri="Page4.xaml#second">
                                    什么是路由事件?
                                </Hyperlink>
                            </Paragraph>
                        </ListItem>
                        <ListItem>
                            <Paragraph>
                                CLR事件足夠完美,為什么還需要路由事件?
                            </Paragraph>
                        </ListItem>
                        <ListItem>
                            <Paragraph>
                                言歸正傳,話路由事件
                            </Paragraph>
                        </ListItem>
                        <ListItem>
                            <Paragraph>
                                路由事件的實例
                            </Paragraph>
                        </ListItem>
                    </List>
                </Section>
                <Paragraph x:Name="first" FontSize="20" Background="AliceBlue">
                    1.    從玉蜂說起,回顧.Net事件模型
                </Paragraph>
                <Paragraph>
                    木木熟悉神雕俠侶的故事,於是他根據“玉蜂傳信”這樣一個故事,信手畫下這樣一幅有趣的圖。
                </Paragraph>
                <BlockUIContainer>
                    <Image Source="routedevent.jpg"/>
                </BlockUIContainer>
                <Paragraph>
                    其實這一幅“玉蜂傳信圖”暗合.Net的事件模型。小龍女是事件的發布者,她發布了事件“我在絕情谷底”;老頑童和黃蓉是事件的訂閱者,不過老頑童並沒有處理該事件,而黃蓉處理了事件,隱約能猜出其中含義;至於可憐的小楊過,則根本沒有訂閱事件,只是苦苦念叨“龍兒,龍兒,你在哪兒……”;而玉蜂正是傳遞信息的事件。事件,事件的發布者和事件的訂閱者構成了.Net事件模型的三個角色。在.Net當中,一個事件是用關鍵字event來表示的。如下代碼所示:
                </Paragraph>
                <Paragraph xml:space="preserve" Background="#88888888">
                    public delegate void WhiteBee(string param); //聲明了玉蜂的委托
    // 小龍女類
    class XiaoLongnv
    {
        public event WhiteBee WhiteBeeEvent;    //玉蜂事件
        public void OnFlyBee()
        {
            Console.WriteLine("小龍女在谷底日復一日地放着玉蜂,希望楊過有一天能看到.....");
            WhiteBeeEvent(msg);
        }
        private string msg = "我在絕情谷底";
}

    // 老頑童類
    class LaoWantong
    {
        public void ProcessBeeLetter(string msg)
        {
            Console.WriteLine("老頑童:小蜜蜂、小蜜蜂,別跑");
        }
    }

    // 黃蓉類
    class Huangrong
    {
        public void ProcessBeeLetter(string msg)
        {
            Console.WriteLine("黃蓉:\"{0}\",莫非......",msg);
        }
}

    // 楊過類
    class YangGuo
    {
        public void ProcessBeeLetter(string msg)
        {
            Console.WriteLine("楊過:\"{0}\",我一定會找她!", msg);
        }
        public void Sign()
        {
            Console.WriteLine("楊過嘆息:龍兒,你在哪兒....");
        }
}
    static void Main(string[] args)
    {
       // 第一步 人物介紹
       XiaoLongnv longnv = new XiaoLongnv();   //小龍女
       LaoWantong wantong = new LaoWantong();  //老頑童
       Huangrong rong = new Huangrong();       //黃蓉
       YangGuo guo = new YangGuo();            //楊過

       // 第二步 訂閱事件,唯獨沒有訂閱楊過的ProcessBeeLetter;
       longnv.WhiteBeeEvent += wantong.ProcessBeeLetter;
       longnv.WhiteBeeEvent += rong.ProcessBeeLetter;
       // longnv.WhiteBeeEvent += guo.ProcessBeeLetter; //楊過是沒有訂閱小龍女的玉蜂事件

       // 第三步 小龍女玉蜂傳信
       longnv.OnFlyBee();

       // 第四步 楊過嘆息
       guo.Sign();
    }
</Paragraph>
                <Paragraph x:Name="second" FontSize="20" Background="AliceBlue">
                    2.    什么是路由事件?
                </Paragraph>
                <Paragraph>
                    什么是路由事件呢?木木很快查看了一下MSDN,MSDN從功能和實現兩種視角給出了路由事件的定義。
                </Paragraph>
                <Paragraph>
                    Functional definition: A routed event is a type of event that can invoke handlers on multiple listeners in an element tree, rather than just on the object that raised the event.
                </Paragraph>
                <Paragraph>
                    Implementation definition: A routed event is a CLR event that is backed by an instance of the RoutedEvent class and is processed by the Windows Presentation Foundation (WPF) event system.
                </Paragraph>
                <Paragraph>
                    雖然木木現在英語功底已經進步了很多,但是這兩個定義還是讓他看得一頭霧水。看來必須得找個例子有點感性的認識(以大家都非常熟悉的Button的Click事件為例,該事件是個路由事件,可以通過Reflector查看ButtonBase的源碼)。
                </Paragraph>
            </FlowDocument>
        </FlowDocumentReader>
    </Grid>
</Page>

上述代碼較長(摘抄自 WPF葵花寶典),使用了一個FlowDocumentReader文本閱讀控件,在其中有多個段落(Paragraph),同時在HyperLink中設置了NavigateUri,可以看到
屬性值除了包含xaml名稱之外,還包含了"#"這樣的符號,沒錯這個就是類似於Html中的,本頁之間的超鏈,通過指定"#元素名稱",在點擊HyperLink之后,就可以導航到Name
為所指定的元素。

 導航工具欄:

上圖中的功能是不是很方便呢,這個在WPF中也很容易的實現.
首先,同樣的設置一個Page為起始頁(WPF會自動添加一個NavigationWindow),然后放置一個按鈕按鈕用於跳轉,點擊之后你會神奇的發現,點擊導航欄的下拉會顯示之前訪問的頁面和當前頁面的鏈接.
不知道細心的童鞋會思考一個問題,這個鏈接的文本是怎么得到的呢,問題問的好,這個鏈接的文本可以來自多個屬性,但是最終卻是有一個會被使用,優先級如下:
JournalEntry.Name(在Page中設置,一個附加屬性)>Page.Title>Page.WindowTitle。
當然,點擊工具欄的前進和后退,也可以導航到之前訪問的頁面去。除了導航欄可以實現前進后退,在其他的按鈕中也是可以的,代碼如下:

            <Button Content="后退" Command="NavigationCommands.BrowseBack"></Button>
            <Button Content="前進" Command="NavigationCommands.BrowseForward"></Button>

只需指定按鈕的Command屬性為對應的命令即可,是不是很簡單呢。


 好了,鏈接的部分就說到這里,之后會和大家分享,導航的高級應用以及頁面更為復雜的周期應用.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM