天天看點

3 XMAL概述3 XMAL概述

3 XMAL概述

         手機曾經是以非常實用為主導的(比如,我可以用它來撥打電話),但在過去幾年裡事情卻發生了戲劇性的變化。盡管,你可以嘗試建立應用程式專注于功能,但是他們可能不會吸引大量的使用者,除非它們有非常出色的使用者界面。這就是一個應用程式吸引人的地方。這意味着你的工作是要找出人們想要什麼,和是什麼使得應用程式易于使用和學習。幸運的是Silverlight自帶了設計界面,還有很多控制應用程式外觀和感覺的方法。建立讓使用者興奮的應用程式會比以往更容易。本章将向你展示如何來實作這一切。

什麼是XMAL

         什麼是可擴充的應用程式标記語言(或XAML)?在Silverlight中XAML是用來設計使用者界面的(包括應用程式的外觀和感覺),但它的确提供了更多的功能。在這裡學到的主要概念是:XAML可以被認為是一個序列化格式,可以很好的被工具處理。它允許我們聲明一個結構化的使用者界面。以這種方式聲明接口友善工具來建立使用者界面和應用程式在運作時使用該檔案。

         我在這裡說的序列化格式意味着什麼哪?XAML非常簡單,讓我們來看一個非常基本的XAML:

         <UserControl x:Class="WinningTheLottery.Sample"

                            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

                            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

                   <Grid>

                            <TextBlock Text="Hello" />

                            <Rectangle Width="100"

                                               Height="100"

                                               Fill="Blue" />

                   </Grid>

         </UserControl>

         XAML是一個XML檔案,它遵循XML基本的規則(例如,單一的頂層容器,區分大小寫)。在這個檔案中我們聲明一個UserControl根元素并包含一個Grid控件,Grid元素中還包含了兩個元素(一個TextBlock和一個Rectangle)。這是這個簡單的使用者界面的基本層次。在解析時,這個XAML檔案被用來在記憶體中建立相同的層次結構。從字面上看,元素的名稱關聯自身到類的名稱。是以當XAML被解析時, UserControl元素提示系統建立一個新的UserControl執行個體。所有用在這裡的類都必須允許空構造函數(.NET要求),以便UserControl類可以被建立。在UserControl自身被建立後,它檢視子元素(Grid)同時在UserControl内部建立一個子元素。最後,它将建立TextBlock和Rectangle并将它們作為Grid的子元素。當TextBlock被建立,它檢查到了attribute(Text),并調用新TextBlock的property的設定方法,用attribute的内容進行指派。它也使用同樣的方式處理Rectangle的衆多attributes。它通過這種方式遵循XAML中相同的層次結構,建造一個記憶體中的對象圖譜。能夠了解你正在使用的XAML是你運作時設計的基礎,這對于了解XAML是如何工作的是非常重要的。

Silverlight 5開發者

         對于那些使用Silverlight 5進行桌面程式開發的開發者來說,手機中的Silverlight 版本是基于Silverlight   4。這意味着你可能已經使用了它缺少的功能,包括隐式資料模闆和相對綁定等等。

XMAL對象屬性

         你在XAML視圖中設定的大多數對象的屬性是簡單的和基于字元串的:

         <Rectangle Fill="Blue" />

         然而,并非所有屬性都可以設定成用簡單的、基于字元串的文法。在背景,許多屬性(在XAML解析時)正試圖将一個字元串attribute轉換成屬性值(使用一種稱為TypeConverter的特殊類型)。例如,Fill屬性它接受的是一個筆刷值,而不是一個顔色。在Fill="Blue"作為XAML解析時,轉換是在一個字元串(例如“Blue”)和一個叫做SolidColorBrush筆刷之間完成的。對于更複雜的值類型(如筆刷),有一個更詳細的文法來設定屬性值:

         <Rectangle>

<Rectangle.Fill>

                   <SolidColorBrush Color="Blue" />

</Rectangle.Fill>

         </Rectangle>

         這個冗長的文法在運作時與先前的例子完全相同。通過在矩形内部添加一個元素,元素的名稱就是對象的名稱,一個點和屬性的名稱(例如,Rectangle.Fill),我們可以用XAML為屬性定義值來代替僅使用字元串。因為并不是所有複雜的屬性值都可以以這種方式來定義,一個轉換可以被執行,這個冗長的文法允許設定屬性值時是一個複雜類型,用一個單獨的字元串來描述将很困難或者不可能。例如,讓我們把SolidColorBrush替換為LinearGradientBrush:

<Rectangle>

<Rectangle.Fill>

<LinearGradientBrush>

<GradientStop Color="Blue" Offset="0" />

<GradientStop Color="White" Offset="0.5" />

<GradientStop Color="Blue" Offset="1" />

</LinearGradientBrush>

                   </Rectangle.Fill>

</Rectangle>

         在這個例子中我們可以看到,定義一個Fill并指定了顔色和補償,僅僅使用一個簡單的字元串不但很難實作,而且會使XAML更加難以了解。通過這種方式,XAML允許你設定非常複雜的屬性而無需實作轉換。随着我們的深入,你将會在XMAL中許多不同的地方看到這是如何使用的。

了解XAML命名空間

         在XAML檔案根元素中是兩個命名空間。在XAML中的命名空間就是XML的命名空間。預設命名空間(xmlns)聲明:這是一個XAML檔案。第二個命名空間(xmlns:x)引入的一些元素和屬性類型都是以x别名為字首的。是以當你看到x:Class,這是一個轉換意味着這個類是定義在第二個命名空間裡的。

         你可以想象命名空間别名作用類似于在.NET中的命名空間。當你添加一個命名空間,它将帶來一些新類型,它們可以在XAML視圖中進行描述。不同于. NET,盡管,你必須使用一個别名(因為所有其他命名空間不是“預設”的命名空間),然後在任何你想要使用該命名空間中的資訊時使用這個别名。在x别名的執行個體中,在這裡的别名“x”隻是一個約定,XAML傾向于使用它。在XML命名空間意義上,你可以将别名改變為任何你想要的名字,但你必須在它的每個引用位置改變它。例如:

    <UserControl foo:Class="WinningTheLottery.Sample"

                   xmlns="..."

                   xmlns:foo="...">

         别名僅僅是:一個代替,是以解析器可以确定你的元素或屬性的命名空間是來自那裡。當我們改變了代替的名稱,它是在文檔的其餘部分你可以使用别名來代替命名空間。

         雖然這些命名空間代表基本XAML命名空間,你可以通過使用命名空間擴充XAML帶來任意.NET類型。如果你定義一個命名空間它指向了一個.NET命名空間和程式集,這些類型也可以在XAML中使用:

    <UserControl x:Class="WinningTheLottery.Sample"

                   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

                   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

                   xmlns:sys="clr-namespace:System;assembly=mscorlib">

                   <Grid>

                            <TextBlock>

                            <TextBlock.Text>

                            <sys:String>Hello</sys:String>

                            </TextBlock.Text>

                            </TextBlock>

                   </Grid>

         </UserControl>

         在這個例子中,XAML“引入”在mscorlib.dll程式集裡的系統命名空間。一旦.NET的命名空間被引入,命名空間中的所有的類型在XAML裡都可以被建立。在XAML中建立任何類型必須符合下列規定:

l  有一個空的,公共的(public)構造函數

l  有公共(public)屬性

         任何遵守這些規則的.NET對象都可以在XAML中建立(并成為你初始對象圖譜中的一部分)。在這一章随着我們繼續深入,你将看到這是如何使用的。        

XAML中的命名

         不同于其他平台,XAML不需要每個在XAML檔案中的對象都需要特殊的命名。事實上,在XAML檔案中為每個對象命名可能是個壞主意。當你需要引用一個已命名對象時(例如從代碼或通過資料綁定),在XAML中命名對象才變得重要。在XAML中命名對象是以一個attribute形式出現的,可以适用于大多數XAML元素:x:Name。例如:

         <UserControl x:Class="WinningTheLottery.Sample"

         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

                  <Grid x:Name="LayoutRoot">

                   <TextBlock Text="Hello"

                                               x:Name="theTextBlock" />

                   <Rectangle Width="100"

                                        Height="100"

                                        Fill="Blue"

                                     x:Name="theRectangle" />

                  </Grid>

</UserControl>

         你将會注意到命名屬性以x:字首(或别名)。在關于命名空間中的讨論中解釋過的,這意味着,通過包含在每一個XAML檔案頂部(預設情況下)的 x命名空間使得命名屬性是可用的。一旦這些對象被命名,XAML中的其他元素,背景代碼通過名字就可以通路到他們 (這兩種情況你将在這一章中都能看到)。這裡使用的名稱必須是惟一的。每個名稱在單一的XAML檔案僅能出現一次。這簡化了命名政策,但也意味着命名範圍不再有意義(在HTML命名範圍有意義)。

可視化容器

         如果你思考的上面顯示例子會發現,你可能忽略了XAML容器的重要性。其中最明顯的可以在Grid元素中發現:

    <UserControl x:Class="WinningTheLottery.Sample"

                   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

                   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

                   <Grid>

                            <TextBlock Text="Hello" />

                   </Grid>

         </UserControl>

         這些容器的目的是允許其他元素以特定的方式放置在Silverlight可視化界面上。盡管這些容器本身通常沒有任何使用者界面,但是他們用來确定如何将不同的XAML元素排列在螢幕上。一些布局容器對于在XAML中進行設計是非常重要的。每個布局容器可以包含一個或多個子元素,并把它們以特色的形式進行布局。在表3.1中,你可以看到常見的視覺容器。

布局容器 描述 是否支援多子元素?
Grid 類似于表格的行列布局;容易進行對齊和調整間距的設計
StackPanel 水準或垂直堆疊單獨的元素
Canvas 基于位置的布局(通過頂部和左側的位置)
ScrollViewer 虛拟的容器,内容可以大于容器,允許使用者通過容器進行滾動
Border 在一個元素附近建立一個簡單的邊界

         這些容器很重要,因為它們被用于确定如何布局元素。其中最重要的是Grid容器,它将你最常使用的容器。Grid是一個支援動态布局,類似于表格的行和列的布局容器。在定義行和列時,你設定了Grid的ColumnDefinitions和/或RowDefinitions屬性。這些屬性使用一個或多個ColumnDefinition或RowDefinition元素,如下所示的代碼:

         <UserControl x:Class="WinningTheLottery.Sample"

                   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

                   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

                   <Grid>

                            <Grid.ColumnDefinitions>

                                     <ColumnDefinition />

                                     <ColumnDefinition />

                            </Grid.ColumnDefinitions>

                            <TextBlock Text="Hello" />

                   </Grid>

         </UserControl>

         你使用ColumnDefinitions和RowDefinitions屬性建立新行和列(如上)。這允許你通過Grid.Column或Grid.Row附加屬性單獨的指定元素在一個特定的行或列(請參閱側欄,什麼是附加屬性?):

         <UserControl x:Class="WinningTheLottery.Sample"

         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

                  <Grid>

                   <Grid.ColumnDefinitions>

                   <ColumnDefinition />

                   <ColumnDefinition />

         </Grid.ColumnDefinitions>

         <TextBlock Text="Hello"

                                     Grid.Column="1" /> <!-- The Second Column -->

         </Grid>

</UserControl>

         TextBlock通過使用附加屬性,表明TextBlock屬于第二列(注意,行和列的數字是以0為開始的)。通過這種方式,Grid通過在前面指定行或列的數量主動的建立列或行。乍一看通過這種方式來建立行和/或列定義似乎羅嗦,但是這是重要的,因為這種定義可以用來設定包含其他的重要資訊。

什麼是附加屬性?

         有些屬性是不相關的,直到它們存在于一些特定的範圍。例如,當一個對象在一個網格裡的時候,能夠告訴XAML它在那列或那行就變得很重要了。但是,同樣的元素在StackPanel裡行或列就沒有概念了。附加屬性是特定類型的屬性,這些屬性隻是在特定的情況下有效。附加屬性的定義是:擁有類型名稱和附加屬性的名稱(例如,Grid.Row)。通過自己公開他們通常在那裡會使用,附加屬性的資訊在類中才是可用的。盡管在XAML中附加屬性通常是這樣使用的,但是附加屬性在一個全局範圍内是可用的屬性。是以你可以定義一個屬性,可以應用于任何XAML對象。容器例如Grid和Canvas,通過公開附加屬性來顯式地讓他們處理布局,對于大多數新的XAML開發人員來說,它們很可能是第一個真正使用的附加屬性。

         例如,在Grid類中,随着Grid對象在它内部進行布局,它通過查詢附加屬性來确定布局一個元素在那行和/或列。字面上的屬性是在運作時附加上的,是以底層元素不需要具有沒必要的屬性(例如行和列)。

         當建立行和列時,你可以使用三個方式(分别)定義高度或寬度,顯示于表格3.2。

表3.2Grid行和列尺寸

類型 描述 例子
Auto 内容基于行或列的大小。尺寸将由  在相應的行或列中最大的對象确定。 <RowDefinition   Height="Auto" />
Pixel 設定行或列為一個特點的尺寸,以Pixel為機關,大對象将被截斷。 <RowDefinition   Height="100" />
Star 基于權值成比例來設定行或列的大小。

<RowDefinition   Height="*" />

<RowDefinition   Height="25*" />

<RowDefinition   Height="0.147*" />

         Auto和Pixel形式的尺寸設定不言自明,但Star形式的尺寸設定需要一些解釋。Star尺寸設定适當的設定行或列的大小基礎在高度或寬度值。例如:

         <UserControl x:Class="WinningTheLottery.Sample"

     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

             <Grid>

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="33*" />

            <ColumnDefinition Width="66*" />

        </Grid.ColumnDefinitions>

             </Grid>

         </UserControl>

         寬度值作為整個大小的權重比例。雖然這看上去類似于百分比(像你可能在Web應用程式使用的),這些數字并不是任意一個100%的比例。例如,更改值為“1 *”和“2 *”産生相同的2-to-1比率,等同于“33 *”和“66 *”。如果使用單獨一顆星(如。“*”),它等同于“1 *”。通過混合使用Grid元素的auto,pixel和star 尺寸設定形式,你可以建立富有彈性的布局(使用star尺寸來靈活的設定元素大小,使用pixel/auto sizing 方式來設計更多的靜态部分)。

         你已經看到了,你可以使用附加屬性來設定一個特定元素在Gird内的行和/或列。Gird類也支援指定RowSpan和ColumnSpan屬性,這意味一個特定的元素可以跨多行和/或列。這将給你更多的靈活性來建立你的表格布局設計,就像這樣:

         <Grid>

<Grid.ColumnDefinitions>

<ColumnDefinition Width="*" />

<ColumnDefinition Width="*" />

<ColumnDefinition Width="*" />

</Grid.ColumnDefinitions>

<Grid.RowDefinitions>

<RowDefinition Height="*" />

<RowDefinition Height="*" />

</Grid.RowDefinitions>

<TextBlock Text="1" />

<TextBlock Text="1"

                            Grid.Row="1" />

                   <TextBlock Text="1"

                            Grid.Column="1" />

                   <TextBlock Text="Across All 3 Columns"

                                               Grid.ColumnSpan="3" />

                   <TextBlock Text="Across Both Rows"

                                               Grid.RowSpan="2" />

         </Grid>

         盡管在某些情況下你可以使用其他布局容器,但你應該适應Grid容器,它會是你最常用的容器。

視覺文法

         Silverlight讓你能夠在手機本身的界面上繪制形狀和顔色。當然你可能不會過多想象真正的進行繪圖,但重要的是你要了解如何利用基本的繪圖元素來進行設計,這對繪制整個XAML故事來說是非常重要的。當你開始使用這些控件時,你會發現這些控件都是由更原始的元素組成,當你想改變控件和其他元素的外觀時,你不得不了解繪圖的堆棧機制。

形狀

         最基本的繪圖元素是Shape。Shape元素是一些被用來進行基礎繪圖的形狀的基類。下面列出了基本繪圖形狀:

l  Line

l  Rectangle

l  Ellipse

l  Polygon

l  Polyline

l  Path

         每種形狀有基本的屬性,例如Height, Width, Fill和Stroke:

         <Grid>

                   <Rectangle Width="100"

                                     Height="100"

                                     Fill="Blue" />

                   <Ellipse Width="200"

                                     Height="50"

                                     Stroke="Black" />

         </Grid>   

         如果你不能通過上述的5種形狀來構成你想要的圖形,那你隻能選擇Path圖形了。Path是一個強大的形狀,它給了你設計任意形狀的權力。Path形狀可以讓你建立打開,關閉,或複合形狀。Path形狀有一個叫做Data的屬性,該屬性用于指定元素的形狀,例如,你可以指定一個包含對象曲線圖的路徑,就像這樣:

<Path Stroke="Black">

         <Path.Data>

                   <PathGeometry>

                            <PathFigure StartPoint="0,50">

                                     <BezierSegment Point1="50,0"

                                                                          Point2="50,100"

                                                                          Point3="100,50"/>

                                     </PathFigure>

                            </PathGeometry>

                   </Path.Data>

         </Path>

         通過将Data屬性指派給PathGeometry元素,指定了一個包含BezierSegment的Path對象(從0,50開始到100,50,包含轉折點50,0和50,100的曲線),你可以畫一條曲線,如圖3.1所示。

圖3.1路徑解釋

         Data屬性包含一個簡化符号來簡化和縮短XAML的大小。簡化符号是同樣類型的資訊,但是存儲在一個單獨的字元串。例如,在圖3.1的曲線可以簡化為:

         <Path Stroke="Black" Data="M  0,50  C  50,0  50,100  100,50" />

         這裡包含了相同的資訊,但是是一個縮寫形式:移動到0,50位置和使用三個點做Bezier曲線。通常路徑是通過工具建立的(例如Expression Blend),制作過程可以得到簡化,但是這個過程确實允許繪制非常複雜的路徑。

筆刷

         到目前為止在許多執行個體中,你已經看到了如何在XAML中使用的顔色名稱(例如,black, red),來表示一個對象是用什麼顔色展示的。事實上,這些顔色是用于建立一個名為筆刷對象的快捷方式。筆刷通常用來繪制界面(例如,使用fill,stroke和background筆刷)。在表格3.3中一些類型的筆刷已經提供給你使用了。

類型 描述 例子
SolidColorBrush 繪制一個純色 <Ellipse   Fill="Blue" />
LinearGradientBrush 繪制一個線性漸變

<Ellipse>

         <Ellipse.Fill>

                  <LinearGradientBrush>

                           <GradientStop   Color="Blue"

                                                      Offset="0"   />

                           <GradientStop   Color="Red"

                                                      Offset="1"   />

                  </LinearGradientBrush>

         </Ellipse.Fill>

</Ellipse>

RadialGradientBrush 繪制一個徑向漸變,焦點定義漸變的開始,而圓定義漸變的終點

<Ellipse>

         <Ellipse.Fill>

                  <RadialGradientBrush>

                           <GradientStop   Color="Blue"

                                                               Offset="0" />

                           <GradientStop   Color="Red"

                                                               Offset="1" />

                  </RadialGradientBrush>

         </Ellipse.Fill>

</Ellipse>

ImageBrush 繪制一個圖形

<Ellipse>

         <Ellipse.Fill>

                  <ImageBrush   ImageSource="/foo.jpg" />

         </Ellipse.Fill>

</Ellipse>

VideoBrush 繪制一個媒體元素

<Ellipse>

         <Ellipse.Fill>

                  <   VideoBrush SourceName="theVideo" />

         </Ellipse.Fill>

</Ellipse>

         XAML元素的每個屬性,如果可以接收brush對象,就可以使用不同類型的筆刷。

顔色

         XAML包含一組内置的顔色。你可以使用這141種命名顔色來指定獨特的顔色,就像這樣:

         <Grid>

                   <Rectangle Fill="Blue"

                                               Stroke="Pink" />

         </Grid>

         雖然,在大多數情況下,已命名的顔色最終不足以處理全部的基礎顔色。由于數以百萬計的顔色可供選擇,XAML需要以更有效地的方式來指定一種顔色。XAML支援HTML中将十六進制字元串轉換為RGB顔色的方式,像這樣:

         <Grid>

                   <Rectangle Fill="#0000FF"

                                               Stroke="#FF0000" />

         </Grid>

    在這種格式中,英鎊符号(#)後接着一組十六進制數字,代表紅色、綠色、藍色被使用數量。六位和三位數字的格式都支援 (例如# FF0000等同于# F00)。此外,XAML擴充了HTML文法以包括一個八位數的版本。在八位數的版本中,前兩個字元代表一個十六進制數字,标明阿爾法通道(或不透明程度):

         <Grid>

                   <Rectangle Fill="#800000FF"

                                     Stroke="#C0FF0000" />

         </Grid>

         在這個例子中,Fill大約50%都是透明的,同時Stroke有大約75%是不透明的(或25%透明)。

文本

         對于繪制基本的文本,TextBlock類是正确的工具。TextBlock是一個繪制文本的簡單容器。它支援屬性選擇,例如基本字型大小、字型、粗細、前景顔色、對齊等等。

<Grid>

         <TextBlock Text="Hello World"

                            Foreground="White"

                            FontFamily="Segoe WP"

                            FontSize="18"

                            FontWeight="Bold"

                            FontStyle="Italic"

                            TextWrapping="Wrap"

                            TextAlignment="Center" />

</Grid>

         除了簡單的文本,TextBlock類還支援簡單的使用簡單内嵌格式使用LineBreak和Run結構。

         <Grid>

                   <TextBlock>

                            Hello World. <LineBreak />This

                            is the second line. The breaking of

                            the lines in the XAML are

                            <Run Foreground="Red">not significant</Run>.

                   </TextBlock>

         </Grid>

         一個LineBreak标明文本會換行,忽略TextWrapping屬性。一個Run是用于包裝一段文本,需要進行不同于TextBlock其他地區的格式化。Run支援TextBlock允許的基本屬性,但是隻将它們應用到Run元素中的文本上,如上所示。TextBlock不是一個處理任何類型的富文本或者處理HTML級别的文的控件,但在大多數情況下的文本操作已經足夠了。

圖像

         雖然簡單的矢量繪圖堆棧對你的Windows Phone 7應用程式的設計來說是非常寶貴的,但你總是需要在應用中使用的圖像的。

         <Image Source="http://wildermuth.com/images/headshot.jpg" />

         Image元素支援JPEG、PNG檔案。它不支援GIF檔案。通過指定Source屬性,圖像元素顯示了你在Source屬性中指定了URI的圖檔。如果指定一個網際網路UR,Image元素将嘗試從網際網路位置下載下傳圖像。Source屬性也支援相對URI:

         <Image Source="headshot.jpg" />

         通過使用一個相對URI,圖像元素嘗試從應用程式本身下載下傳圖檔。你可以添加一個現有的圖像到Silverlight項目,隻需要從項目菜單選擇“添加|現有項目”。一旦你有了一個圖像作為項目的一部分,它将被打包到你的應用程式中。是以,你可以簡單地使用相對URI指定源屬性。相對的URI是相對于項目根目錄的。是以,如果你把一個圖像在一個項目檔案夾,URI需要導航到該路徑:

         <Image Source="Images/headshot.jpg" />

         作為應用程式的一部分存儲你的圖像對靜态圖像(例如按鈕圖示,背景等等)來說是典型的做法。

         預設情況下,Image元素設定為伸縮圖像大小來适應元素。你可以通過指定Stretch屬性伸縮圖像。有效的伸縮類型包括:

l  None:沒有伸縮執行。

l  Uniform: 拉伸圖像,保留了原來的長寬比,來适應Image元素的架構。這是預設的。

l  UniformToFill:拉伸圖像,保留了原來的長寬比,來填充Image元素。如果從該圖像與Image元素的長寬比不同,圖像将被裁剪,以适應差異。

l  Fill:拉伸圖像填充Image元素不保持長寬比。

         圖3.2展示了不同類型伸縮的例子。

圖3.2圖像伸縮

         當建立Image元素時,你可以簡單的指定Stretch屬性,像這樣:

         <Image Source="Images/headshot.jpg" Stretch="UniformToFill" />

         因為圖像元素也是設計文法的一部分,你可以指定大小通過使用高度和寬度或使用容器屬性像任何其他元素一樣 (例如 Grid.Row/Column, Margin, VerticalAlignment等)。

轉換和動畫

         現在你已經有了設計應用程式外觀的基本構模組化塊,讓我們談談建立應用程式的“感覺”。應用程式的感覺是它與使用者進行互動的方式。互動的層次取決于應用程式的性質,但是對使用者來說許多應用程式應該感覺還活動着。通常這是通過給使用者微妙的回報來完成的,包括改變UI外觀來響應使用者的行為,或使用諸如觸覺(例如震動)回報。這種回報是重要的,以幫助使用者知道他是在做某事。一個常見的例子是曆史悠久的按鈕對象。在一個典型的桌面作業系統,當你把滑鼠移動到一個按鈕,它改變它的外觀來告訴你你在按鈕上。當你點選它時,它會改變它的外觀給你留下了這樣的印象,它确實被按下了(像現實中的按鈕)。

         這種回報確定你可以放心,按下按鈕做的事情正是你所希望的。一些網站缺少這種回報,這使使用者感到迷惑(他們常常不知道缺少什麼)。這就是轉換和動畫可以幫助你提升你的使用者界面設計的地方。

轉換

         讓我們從轉換開始。轉換的想法是簡單的改變一個元素在螢幕上的繪制方式,讓我看一個簡單的矩形:

         <Grid>

                   <Rectangle Width="100"

                                     Height="100"

                                     Fill="Red" />

         </Grid>

         正如你期望的,這個長方形,将會被繪制為一個簡單的正方形。讓我們看看當我們加入轉換會發生什麼(通過将轉換指派給Rectangle的RenderTransform屬性):

<Grid>

         <Rectangle Width="100"

                                     Height="100"

                                     Fill="Red">

                   <Rectangle.RenderTransform>

                                     <RotateTransform Angle="30" />

                   </Rectangle.RenderTransform>

         </Rectangle>

</Grid>

         通過使用一個RotateTransform,你可以確定對象可以保持為一個矩形,但在繪制時,轉化被應用了(如圖3.3)。

圖3.3轉換在進行

         對單個元素使用轉換很少是正确的選擇;通常一個轉換應用于整個容器來改變容器的外觀:

<Canvas>

         <Canvas.RenderTransform>

                   <RotateTransform Angle="30"

                                                        CenterX="150"

                                                        CenterY="150" />

         </Canvas.RenderTransform>

         <Ellipse Width="300"

                            Height="300"

                            Stroke="Black"

                            Fill="Yellow"

                            StrokeThickness="2" />

         <Ellipse Fill="Black"

                            Width="50"

                            Height="50"

                            Canvas.Left="50"

                            Canvas.Top="75" />

         <Ellipse Fill="Black"

                            Width="50"

                            Height="50"

                            Canvas.Left="200"

                            Canvas.Top="75" />

         <Path Stroke="Black"

                            StrokeThickness="5"

                            Data="M 50,200 S 150,275 250,200" />

</Canvas>

在這種情況下整個笑臉設計被旋轉了(如圖3.4)。

圖3.4整個容器轉換

         表3.4描述了不同類型的轉換并提供了示例。

表3.4 轉換類型

類型 描述 例子
RotateTransform 在一個對象或對象樹上執行二維旋轉(在二維 x-y 坐标系内圍繞指定點順時針旋轉對象。) <RotateTransform   Angle="30" />
SkewTransform 在一個對象或對象樹上執行二維扭曲。

<SkewTransform   AngleX="30"

                                    AngleY="75"   />

ScaleTransform 在二維 x-y 坐标系内縮放對象或對象樹

<ScaleTransform   ScaleX="1.5"

                                    ScaleY=".75"   />

TranslateTransform 在二維 x-y 坐标系内平移(移動)對象或對象樹。

<TranslateTransform   X="1.5"

                                             Y=".75" />

CompositeTransform 以一個優先順序執行一個混合的旋轉、傾斜、伸縮和變形轉換

<CompositeTransform

         Rotation="30"

         ScaleX="1.5"

         TranslateX="150" />

         你可以單獨的使用4種基本類型轉換,或者如果你需要混合使用轉換(例如縮放和旋轉),你可以使用複合轉換組合多個轉換。

動畫

         雖然在應用程式中使用動畫的想法可能會讓你聯想到創造下一個賣座動畫大片,但這不是動畫的全部。動畫隻是随着時間的推移來改變XAML元素屬性的一種方法。例如,一個簡單的動畫來改變矩形的寬度應該像這樣:。

         <DoubleAnimation Storyboard.TargetName="theRectangle"

                                               Storyboard.TargetProperty="Width"

                                               From="50"

                                               To="250"

                                               Duration="00:00:05" />

         動畫元素告訴一個特定的屬性如何随時間變化。這個例子展示了如何更改一個名為theRectangl的元素在五秒鐘内寬度從50到250。附加屬性(Storyboard.TargetName 和Storyboard.TargetProperty)暗示了事實上動畫并不是自己執行的,而是宿主在一個叫做故事闆的容器中執行的。例子:

         <Grid.Resources>

                   <Storyboard x:Name="theStory">

                            <DoubleAnimation Storyboard.TargetName="theRectangle"

                                                                 Storyboard.TargetProperty="Width"

                                                                 From="50"

                                                                 To="250"

                                                                 Duration="00:00:05" />

                            </Storyboard>

         </Grid.Resources>

         故事闆是内嵌在Resources節中(通常是在主要的容器或使用者控件級别)并命名,以便可以通過代碼來執行和控制它。動畫的工作單元是Storyboard。故事闆可以包含一個或多個動畫,但所有動畫是并發執行(非連續)。是以,如果我們擴充這個故事闆來包含兩個動畫:

         <Grid.Resources>

                   <Storyboard x:Name="theStory">

                            <DoubleAnimation Storyboard.TargetName="theRectangle"

                                                                 Storyboard.TargetProperty="Width"

                                                                 From="50"

                                                                 To="250"

                                                                 Duration="00:00:05" />

                            <DoubleAnimation Storyboard.TargetName="theEllipse"

                                                                 Storyboard.TargetProperty="Opacity"

                                                                 From="1"

                                                                 To="0"

                                                                 Duration="00:00:03" />

                   </Storyboard>

         </Grid.Resources>

         當這個故事闆執行時,兩個動畫時是同一時間執行的(再次并行), 盡管是動畫本身針對的是不同對象的不同屬性。

         到目前為止你看到的動畫都是DoubleAnimation類型的。這些動畫都是被用來更改一個數字(一個雙精度值)。也有動畫會改變顔色(ColorAnimation)和向量(PointAnimation)。所有這三種類型的動畫在一緻的時間架構(被稱為時間軸動畫)下更改值。還有動畫稱為關鍵幀動畫(keyframe animations)。這些動畫也随着時間的變化改變屬性,但是這樣的計算基于在動畫中特定的時間值。例如:

         <DoubleAnimationUsingKeyFrames Storyboard.TargetName="theRectangle"

                                                                           Storyboard.TargetProperty="Height">

                   <LinearDoubleKeyFrame KeyTime="00:00:00" Value="50" />

                   <LinearDoubleKeyFrame KeyTime="00:00:01" Value="150" />

                   <LinearDoubleKeyFrame KeyTime="00:00:03" Value="200" />

         </DoubleAnimationUsingKeyFrames>

         對于每個時間軸動畫來說這些是關鍵幀動畫(例如雙精度,點和顔色)但是他們以UsingKeyFrames作為命名的字尾,如上所示。故事闆的附加屬性仍然是用于辨別動畫的目标,但是,不同于一個從某個值到指定值的簡單動畫,而是使用一個或多個關鍵幀。例如,LinearDoubleKeyFrame的元素指定在某個時間,值應該是一個具體的數值屬性。

         在這種情況下,在動畫開始時高度應在50開始;在第一秒内迅速轉移到150;最後慢下來,用最後兩秒時間移動到200。在幀之間插值取決于關鍵幀的類型。在這個例子中插值是線性的。你還可以分别使用樣條和離散來實作曲線插值和階梯插值。

         有了這些工具,你應該能夠創造出微妙的互動效果,給使用者的印象是,他與現實世界的對象進行互動。

XAML樣式

         當編寫代碼時,這是習慣,采取共同的代碼塊和重用他們的方法,包括建立基類,建立靜态類,甚至建立可重用的類庫。XAML有同樣有建立可重用設計的需求。

不過,這種可重用性更多的是關于建立一緻的應用程式外觀,而無需複制相同的代碼。考慮一下這個普通的XAML:

         <TextBox x:Name="nameBox"

                            FontSize="36"

                            ontFamily="Segoe WP"

                            FontWeight="Black"

                            BorderBrush="Blue"

                            Foreground="White"

                            HorizontalAlignment="Stretch" />

         <TextBox x:Name="emailBox"

                            FontSize="36"

                            FontFamily="Segoe WP"

                            FontWeight="Black"

                            BorderBrush="Blue"

                            Foreground="White"

                            HorizontalAlignment="Stretch" />

         在這個XAML中許多屬性從一個文本框複制到其他文本框。如果我們需要改變的任何一個屬性,我們将這些拷貝到其他地方,來保持UI的一緻性。此外, Foreground和BorderBrush使用的顔色能夠或者應該納入整體的外觀和感覺的考慮。很有可能,我們希望使用筆刷來保持一緻性,不僅僅是從文本框到文本框,還可跨整個應用程式。這就是樣式和資源的由來。

了解資源

         第一層的一緻性是使用共享資源。當建立一個應用程式時,你通常會希望在整個應用程式使用常見的顔色或筆刷。Silverlight允許你建立對象用于多個區域通過指定在Resources節并使用x:Key屬性來标示對象。例如,你可以在Resources節定義一個SolidColorBrush,像這樣:

         <Grid x:Name="LayoutRoot">

                   <Grid.Resources>

                            <SolidColorBrush x:Key="mainBrush"

                                                                 Color="Blue" />

                   </Grid.Resources>

         ...

         </Grid>

         每個從FrameworkElement繼承的類(這意味着大多數XMAL元素)支援一個Resources集合。我們可以通過使用StaticResource标記擴充引用這些命名元素,就像這樣:

         <Grid x:Name="LayoutRoot">

                   <Grid.Resources>

                            <SolidColorBrush x:Key="mainBrush"

                                                                 Color="Blue" />

                   </Grid.Resources>

                   <TextBlock Foreground="{StaticResource mainBrush}"

                                               Text="Hello World" />

         ...

         </Grid>

         StaticResource标記擴充告訴XAML解析器用main Brush來代替foreground。你可以在許多地方使用資源,以便将他們從以後的變更中隔離出來,當你改變将main brush更改為LinearGradientBrush,它會級聯更改每一個使用StaticResource的地方。

         StaticResource标記擴充通過檢索XAML文檔通過正确的名稱找到資源(通過層次),甚至繼續檢索超越XAML文檔的開頭。上面的XAML檔案是在手機應用程式項目的App.xaml檔案中。通常情況下,你可以把任何應用程式範圍内使用的資源存放在這裡。例如,如果App.xaml檔案看起來像這樣:

         <Application x:Class="PhoneControls.App"

                                     xmlns="..."

                                     xmlns:x="..."

                                     xmlns:phone="..."

                                     xmlns:shell="...">

                   <!--Application Resources-->

                   <Application.Resources>

                            <SolidColorBrush x:Key="mainBrush"

                                                                 Color="Blue" />

                   </Application.Resources>

         ...

         </Application>

      mainBrush将被定義在應用程式級别,這樣任何XAML檔案想用筆刷都可以這麼做,就像這樣:

         <Grid x:Name="LayoutRoot">

                   <TextBlock Foreground="{StaticResource mainBrush}"

                                               Text="Hello World" />

         ...

         </Grid>

         盡管這個示例顯隻示了一個筆刷(這是一個非常普遍的資源),但是資源不僅僅隻限于筆刷。建立的任何對象都可以用這種方式。此外,當你要跨項目共享這些資源,你可以使用 ResourceDictionary對象來完成。資源字典也是XAML檔案,包含了共享資源,可以通過合并字典導入到App.xaml中。這些字典可以是平面的XAML檔案,也可以包含在單獨程式集中,引用到你的手機應用程式。合并字典的詳細資訊,請參閱說明文檔。

了解樣式

         雖然共享資源可以幫助你定義一個共同的外觀和感覺,樣式堆棧通過允許你在一個公共位置指定控件的預設值,擴充了這個想法。Style對象允許你建立這些預設屬性:

         <Style TargetType="TextBox"

                            x:Key="mainTextBox">

                   <Setter Property="FontSize"

                                     Value="18" />

                   <Setter Property="FontFamily"

                                     Value="Segoe WP Bold" />

         </Style>

         Style對象采用對象類型方式,這些對象類型可以應用Style,然後是一系列Setter對象,這些Setter對象定義了屬性的預設值。在這個例子中Style為一個文本框是提供FontSize和FontFamily屬性的預設值。你可以通過StaticResource标記擴充将它映射到元素的樣式屬性,應用這種風格到一個對象上,就像這樣:

         <TextBox Style="{StaticResource mainTextBox}" />

         使用StaticResource标記擴充來設定文本框的Style屬性,TextBox的預設屬性值使用Style來設定。樣式僅僅是命名的資源,是以你通常可以的将他們與其他資源一起放到App.xaml檔案中。另外,你可以在你的樣式中使用其他資源,像這樣:

         <Application.Resources>

                  <SolidColorBrush x:Key="mainBrush"

                                                        Color="Blue" />

                  <Style TargetType="TextBox"

                                     x:Key="mainTextBox">

                            <Setter Property="FontSize"

                                              Value="18" />

                            <Setter Property="FontFamily"

                                              Value="Segoe WP Bold" />

                            <Setter Property="Foreground"

                                              Value="{StaticResource mainBrush}" />

                   </Style>

         </Application.Resources>

         通過這種方式,共享資源可能級聯應用到樣式堆棧中。另外,樣式自身也可以級聯通過使用BasedOn屬性:

         <Application.Resources>

                   <SolidColorBrush x:Key="mainBrush"

                                                        Color="Blue" />

                   <Style TargetType="TextBox"

                                     x:Name="baseTextBox">

                            <Setter Property="FontSize"

                                               Value="18" />

                            <Setter Property="FontFamily"

                                               Value="Segoe WP Bold" />

                   </Style>

                   <Style TargetType="TextBox"

                                     x:Key="mainTextBox"

                                     BasedOn="{StaticResource baseTextBox}">

                            <Setter Property="Foreground"

                                               Value="{StaticResource mainBrush}" />

                   </Style>

         </Application.Resources>

         最後,樣式是可以多态的。換句話說,TargetType應用到一個基類時,還可以應用到這個類型的全部對象上。例如:

         <Application.Resources>

                   <SolidColorBrush x:Key="mainBrush"

                                                        Color="Blue" />

                   <Style TargetType="Control"

                                     x:Name="baseControl">

                            <Setter Property="BorderBrush"

                                               Value="Black" />

                   </Style>

                   <Style TargetType="TextBox"

                                     x:Key="mainTextBox"

                                     BasedOn="{StaticResource baseControl}">

                            <Setter Property="FontSize"

                                               Value="18" />

                            <Setter Property="FontFamily"

                                               Value="Segoe WP Bold" />

                            <Setter Property="Foreground"

                                               Value="{StaticResource mainBrush}" />

                   </Style>

         </Application.Resources>

         由于基礎樣式的TargetType是Control,它可以被任何控件用來繼承樣式(或任何從Control類派生的控件樣式)。

隐式樣式

         當你經常使用命名樣式(和StaticResource标記擴充名),以配合一個XAML元素的樣式(如顯示在前面節),你也可以建立适用于預設情況下元素的樣式。這些被稱為隐式樣式。要建立一個隐式樣式,你的樣式絕不能包括一個Key。例如:

         <Application.Resources>

                   <Style TargetType="TextBox">

                            <Setter Property="FontSize"

                                               Value="18" />

                            <Setter Property="FontFamily"

                                               Value="Segoe WP Bold" />

                   </Style>

         </Application.Resources>

         通過删除樣式上的X:Key,樣式将應用到每個TargetType的元素上(例如TextBox)。如果一個元素指定使用了一個明确的樣式(例如,通過樣式名),隐式樣式完全被取代。是以,你可以任選一種隐式或顯式樣式應用到XAML中特定的元素,但不是兩個。在大多數情況下,你有一個隐式樣式來控制控件的主要風格,然後使用明确的樣式來處理特定用途的控件。

         一個重大的差別在隐式風格的TargetType不是多态的,是以它隻适用于特定的類型,而不是派生類型。例如,如果你建立一個“Control”類型的隐式風格,它将隻應用于XAML具體控件類的元素;文本框和按鈕元素(繼承于Control)将不使用這種樣式。樣式的其他規則(例如使用基礎資源、級聯樣式)都适用。

我們在哪兒?

         本章向你介紹了Silverlight for Windows Phone 7中基礎的XAML生态系統。有了這些概念,你可以開始為你的應用程式設計使用者界面了。我隻觸及了XAML本質的表面,是以你不應該假設,我在本章描述了每一個元素和每個屬性。利用幫助文檔來充實你對Silverlight中 XAML的了解。這一章重點在于了解XAML的文本表示,下一章将介紹在你的應用程式與使用者進行互動時,如何使用控件。

轉載于:https://www.cnblogs.com/newetms/archive/2012/08/28/2660553.html

繼續閱讀