程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 《Programming WPF》翻譯 第5章 3.命名屬性

《Programming WPF》翻譯 第5章 3.命名屬性

編輯:關於.NET

通過把同樣的內嵌樣式提升到資源中(正如第一章介紹的),我們可以給它 一個名字,以及按名字使用它在我們的Button實例上,正如示例5-5。

示例5-5

<!-- Window1.xaml -->
<Window >

  <Window.Resources>
    <Style x:Key="CellTextStyle">
      <Setter Property="Control.FontSize" Value="32" />
      <Setter Property="Control.FontWeight" Value="Bold" />
    </Style>
  </Window.Resources>

  <Button Style="{StaticResource CellTextStyle}"  x:Name="cell00" />

</Window>

在示例5-5中,我們在屬性中使用到Control前綴取代Button前綴,從而允許 樣式更廣泛的應用,正如我們將要看到的。

5.3.1 TargetType屬性

方便起見,如果所有的屬性可以在一個共享類中設置,像我們示例中的 Control,我們可以提升這個類的前綴,放入TargetType屬性中,並將其從屬性 的名稱中移除掉。如示例5-6所示。

示例5-6

<Style x:Key="CellTextStyle" TargetType="{x:Type Control}">
  <Setter Property="FontSize" Value="32" />
  <Setter Property="FontWeight" Value="Bold" />
</Style>

當提供了一個TargetType屬性,你能夠只設置該類型可接受的屬性。如果你 想要在繼承樹下擴展一組大量的屬性,你可以通過使用一個派生類型來做到這些 ,如示例5-7。

示例5-7

<Style x:Key="CellTextStyle" TargetType="{x:Type Button}">

  <!-- IsCancel is a Button-specific property -->
  <Setter Property="IsCancel" Value="False" />
  <Setter Property="FontSize" Value="32" />
  <Setter Property="FontWeight" Value="Bold" />
</Style>

在這種情形中,IsCancel屬性只在Button上有效,因此,為了設置它,我們 需要為了這個類型轉換TargetType屬性。

你可能想知道為什麼我設置FontSize為“32”而不是“32pt”,當詳細的指 定了字體大小時,後者在一條直線上占得更多,。這兩種表示法明顯是不相等的 。(前者是pixels,而後者是points)。由於這種寫法,我使用pixels,WPF樣 式使用了一個不加前綴的屬性,允許“32pt”明確指定為FontSize,然而前綴屬 性並不是這樣。例如,下面的代碼能正常運行(假設Target已經被設置了):

    <Setter Property=”FontSize” Value=”32pt” />

而以下並沒有這麼做(不管TargetType是否被設定)

    <Setter Property=”Control.FontSize” Value=”32pt ” />

希望在你讀到這裡的時候,這個問題已經被修復了。(而且沒有被其它所取 代)

5.3.2樣式復用

除了將你從要為每一個屬性名輸出類前綴的名稱解救出來之外,TargetType 屬性還會檢查所有應用了樣式的類是那個類型或派生的類型的一個實例。這意味 著一旦我們將TargetType在Control中設置,我們就能將其應用到一個Button元 素,而不是一個TextBlock元素,前者最終派生於Control,而後者不是。

另一方面,盡管Control和TextBlock都共享共同的FrameworkElement祖先, FrameworkElement並沒有定義一個FontSize依賴屬性,因此一個帶有 FrameworkElement.TargetType的樣式不會讓我們設置FontSize屬性,因為它並 不在那裡,盡管事實上Control和TextBlock都有一個FontSize屬性。

即使在Control中設置TargetType,我們獲得了一個跨越類來復用樣式的尺度 ,這些類是派生於Control的,如Button,Label,Window等等。盡管如此,如果 我們從樣式中一起去除TargetType屬性,我們獲得了一個跨越控件來復用樣式的 尺度,不再有一個公有的基礎,而是共享一個依賴屬性的實現。根據我的經驗, 我發現依賴屬性跨越類共享了同樣的名稱,如Control.FontSize和 TextBlock.FontSize,還共享了一個實現。這意味著即使Control和TextBlock各 自定義了它們的FontSize屬性,在運行時它們共享這個屬性的實現,所以我可以 編寫示例5-8那樣的代碼。

示例5-8

<Style x:Key="CellTextStyle">
  <Setter Property="Control.FontSize" Value="32" />
</Style>

<!-- derives from Control -->
<Button Style="{StaticResource CellTextStyle}"  />

<!-- does *not* derive from Control -->
<TextBlock Style="{StaticResource CellTextStyle}"  />

在示例5-8中,我從樣式定義中去除了TargetType屬性,使用了替代的雷前綴 在每個樣式設置的屬性上。這個樣式能被應用到一個Button元素,正如你期望的 ,也能應用到一個TextBlock控件上,隨著FontSize在樣式中明確地設定。這樣 工作的原因是Button從Control獲取它的FontSize依賴屬性定義,而TextBlock, 提供它的FontSize依賴屬性定義,共享由TextElement實現的FontSize依賴屬性 。圖5-2顯示了元素間的關系及他們的依賴屬性實現。

如圖5-2所示,如果我們需要,我們可以按照TextElement重新定義我們的樣 式,即使它陷入機成熟,既不是Control也不是TextBlock,如示例5-9所示。

圖5-2

示例5-9

<Style x:Key="CellTextStyle">
  <Setter Property="TextElement.FontSize" Value="32" />
</Style>

<Button Style="{StaticResource CellTextStyle}"  />
<TextBlock Style="{StaticResource CellTextStyle}"  />

更進一步,如果我們想要定義一個包含屬性的樣式,這些屬性沒有被每個我 們要應用樣式的元素共享,我們也可以這麼做,如示例5-10。

示例5-10

<Style x:Key="CellTextStyle">
  <Setter Property="TextElement.FontSize" Value="32" />
  <Setter Property="Button.IsCancel" Value="False" />
</Style>

<!-- has an IsCancel property -->
<Button Style="{StaticResource CellTextStyle}"  />

<!-- does *not* have an IsCancel property -->
<TextBlock Style="{StaticResource CellTextStyle}"  />

在示例5-10中,我們已經添加了Button.IsCancel屬性在CellTextStyle中, 以及將其應用到有這個屬性的Button元素,而TextBlock元素則沒有這個屬性。 那好,在運行時,WPF將應用依賴屬性到擁有這個屬性的元素上

WPF的應用樣式到對象的能力,並不要求對象有所有的屬性定義在樣式中,類 似的應用到Word的Normal樣式,包含一個字體類型屬性,同時包括一段文本和一 個圖片。即使Word知道圖片沒有字體類型,它仍然應用到Normal樣式的一部分使 之確實有意義。(正如對齊屬性),忽略其余的內容。

回到我們的示例,我們可以在一個新行中的TextBlock上使用CellTextStyle ,以顯示輪到誰了,如示例5-11所示:

示例5-11:

<Window.Resources>
  <Style x:Key="CellTextStyle">
    <Setter Property="TextElement.FontSize" Value="32" />
    <Setter Property="TextElement.FontWeight" Value="Bold" />
  </Style>
</Window.Resources>
<Grid Background="Black">
  <Grid.RowDefinitions>
    <RowDefinition />
    <RowDefinition />
    <RowDefinition />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>
  <Grid.ColumnDefinitions>
    <ColumnDefinition />
    <ColumnDefinition />
    <ColumnDefinition />
  </Grid.ColumnDefinitions>
  <Button Style="{StaticResource CellTextStyle}"  />

  <TextBlock
    Style="{StaticResource CellTextStyle}"

    Foreground="White"
    Grid.Row="3"
    Grid.ColumnSpan="3"
    x:Name="statusTextBlock" />
</Grid>
</Window>

跨越不同控件的樣式復用給我的應用程序一致的外觀,如圖5-3所示。

你應該注意的是圖5-3的狀態文字,盡管按鈕中的文字是黑色的。由於黑色是 默認的文字顏色,如果我們想要狀態文字的顯示相對於黑色背景,我們不得不將 顏色改變為其它,因此需要在TextBlock上設置Foreground屬性為白色。聯合樣 式,每一個示例屬性Setting都工作正常,而且,你可以聯合兩種設置屬性值的 技術正如你看到的。

圖5-3

5.3.3

進一步,如果我們想要在一個指定的實例上復寫一個樣式屬性,通過在實例 上設置屬性,我們是可以做到的,正如示例5-12。

示例5-12

<Style x:Key="CellTextStyle">
  <Setter Property="TextElement.FontSize" Value="32" />
  <Setter Property="TextElement.FontWeight" Value="Bold" />
</Style>

<TextBlock
  Style="{StaticResource CellTextStyle}"
  FontWeight="Thin"  />

在示例5-12中,在TextBlock實例屬性上設置FontWeight,優先於在樣式屬性 上設置FontWeight。

5.3.4繼承樣式屬性

為了完成oo的三個特征:復用,復寫,繼承,你可以從一個基礎樣式繼承一 個樣式,添加新屬性或者重寫已有屬性,如示例5-13所示。

示例5-13

<Style x:Key="CellTextStyle">
  <Setter Property="TextElement.FontSize" Value="32" />
  <Setter Property="TextElement.FontWeight" Value="Bold" />
</Style>
<Style x:Key="StatusTextStyle" BasedOn="{StaticResource CellTextStyle}">
  <Setter Property="TextElement.FontWeight" Value="Thin" />
  <Setter Property="TextElement.Foreground" Value="White" />
  <Setter Property="TextBlock.HorizontalAlignment" Value="Center" />
</Style>

BaseOn樣式屬性用於指定一個基礎樣式。在示例5-3中,StatusTextStyle樣 式繼承了所有CellTextStyle屬性的設置,復寫了FontWeight,以及Foreground 和HorizontalAlignment的設置。注意到,HorizontalAlignment屬性使用了 TextBlock前綴,這是因為TextElement沒有HorizontalAlignment這個屬性。

我們當前使用的樣式了引起了TTT游戲看上去如圖5-4。

圖5-4

到目前為止,我們的應用程序相當不錯,尤其是狀態文字上的細字體寬度, 但是我們可以做得更好。

5.3.5編程上設置樣式

一旦一個樣式有了名字,從我們的代碼中是很好利用的。例如,我們可能決 定要每個玩家有自己的樣式。在這種情形中,在xaml中,在編譯期使用命名屬性 不會成功,因為我們想基於內容設置樣式,而內容是直到運行期才知道的。然而 ,沒有什麼要求我們去設置一個控件靜態的Style屬性;我們也可以編程實現, 如示例5-14。

示例5-14

public partial class Window1 : Window {
  void cell_Click(object sender, RoutedEventArgs e) {
    Button button = (Button)sender;

    // Set button content
    button.Content = this.CurrentPlayer;

    if( this.CurrentPlayer == "X" ) {
      button.Style = (Style)FindResource("XStyle");
      this.CurrentPlayer == "O";
    }
    else {
      button.Style = (Style)FindResource("OStyle");
      this.CurrentPlayer == "X";
    }

  }

}

在示例5-14中,無論玩家何時點擊,除了設置按鈕內容之外,我們從窗體資 源中拉出一個命名樣式並將其設置給按鈕的樣式。這假設了一對命名樣式在窗體 級別被定義,如示例5-15。

示例5-15

<Window.Resources>
  <Style x:Key="CellTextStyle">
    <Setter Property="TextElement.FontSize" Value="32" />
    <Setter Property="TextElement.FontWeight" Value="Bold" />
  </Style>
  <Style x:Key="XStyle" BasedOn="{StaticResource CellTextStyle}">
    <Setter Property="TextElement.Foreground" Value="Red" />

  </Style>
  <Style x:Key="OStyle" BasedOn="{StaticResource CellTextStyle}">
    <Setter Property="TextElement.Foreground" Value="Green" />
  </Style>
</Window.Resources>

隨著這些適當位置的樣式,以及伴隨著內容的設置按鈕樣式的代碼,我們得 到圖5-5。

注意到,所有的X和O都根據命名玩家的樣式設置了顏色。在這種特定的情形 中(以及其他情形),數據觸發器(在5.6中討論)應該被優先選擇用來以編程 方式設置樣式,但是你不知道什麼時候將要必須去堵塞。

作為所有xaml的構造器,你可以自由地以編程方式創建樣式。附錄A是一個好 的介紹——關於如何考慮在xaml和代碼之間來來往往的進行。

圖5-5

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved