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

《Programming WPF》翻譯 第6章 2.資源與樣式

編輯:關於.NET

WPF的樣式機制以來於資源體系來定位樣式。正如你在第5章看到的,樣式在 元素的資源片段中定義,而且樣式通過其名字被引用,正如示例6-18所示:

示例6-18

<Window x:Class="ResourcePlay.Window1" Text="ResourcePlay"
    xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005">

     <Window.Resources>
        <Style x:Key="myStyle">
            <Setter Property="Button.FontSize" Value="36" />
        </Style>
    </Window.Resources>

    <Grid>
        <Button Style="{StaticResource myStyle}">Hello</Button>
    </Grid>
</Window>

然而,如何定義一個樣式,使之自動的應用到一個元素,而無需顯示指定要 引用的資源——這是可以實現的,而且非常有用——當你需要把一個樣式應用到 具有獨特類型的所有元素上,而不是把資源引用添加到每個元素上。示例6-19對 示例6-18做了一些修改,展示了隱式聲明這一功能。

示例6-19

<Window x:Class="ResourcePlay.Window1" Text="ResourcePlay"
    xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005">

     <Window.Resources>
        <Style TargetType="{x:Type Button}">
            <Setter Property="Button.FontSize" Value="36" />
        </Style>
    </Window.Resources>

    <Grid>
        <Button>Hello</Button>
    </Grid>
</Window>

注意到Button標簽不再有其特定的Style屬性。然而,這個樣式仍然通過 TargetType應用到Button上,而不是定義一個key,這個樣式使用x:Type來設置 TargetType,於是通知XAML為這個TargetType類提供一個System.Type對象。

如果FrameworkElement沒有顯示指定Style,它總是會尋找一個使用其自身類 型的樣式資源,作為其Target類型。

如果你建立了一些非樣式的資源,例如SolidColorBrush,同時設置其x:Key 為某個UI元素的類型,如果試著使用該元素的類型就會發生一個錯誤。這是因為 你創建了一個帶有TargetType的Style卻沒有指定x:Key,x:Key隱式地設置為同 TargetType一樣。這個Key用於定位style。因此,通常而言,你應該避免將 x:Key設置為Type類型的對象。

因為元素會在資源中搜索它的樣式,你可以利用系統級別的資源。你可以定 義一個樣式資源在局部范圍內,如果你僅僅希望影響少量的元素;或者在一個廣 義范圍上,例如Window.Resource;或者在應用程序的范圍。而且樣式可能延及 到系統級別。這種樣式和資源之間的聯系是使用皮膚和主體的關鍵

6.2.1皮膚和主題

皮膚和主題都是控制UI外觀的技術。主題,是一種系統級別的外觀,例如 Windows2000的經典外觀,又如Windows XP的“Luna”主題。皮膚是一個特定於 應用程序的外觀,正如各種各樣具有不同樣式的媒體播放程序,例如WinApp和 Windows Media Player

皮膚和主題都可以在WPF實現,作為一組資源應用於需要該樣式的控件

既然皮膚的意圖在於控制一個特定應用程序的外觀,它將為標准控件提供更 多的樣式,可以在應用程序的指定部分定義各種各樣有命名的資源。例如,音樂 播放器可能使用一個ListBox用來顯示歌曲列表。皮膚可以為之提供一個特定的 外觀而不用影響應用程序中其他的ListBox。因此應用程序可以為這個ListBox設 置特定的命名的樣式,同時要在這個樣式中支持這個樣式。對於這種特定情形, 提供這樣一個樣式是可選擇的,但是在其他情形中,應用程序需要皮膚提供提供 指定的資源。例如,如果應用程序中有一個工具條,皮膚可能就需要提供資源並 在其中為這個工具條定義圖像。

同樣,主體是用於所有應用程序,因此,其必須為所有類型的控件提供模板 和樣式。比較而言,一個皮膚是特定於應用程序的,所以它不必提供廣泛全面的 一組樣式。如果應用程序並不使用每一個單獨的控件類型,皮膚只需要為那些在 應用程序中出現的控件提供樣式。示例6-20和示例6-21為一個相當簡單的皮膚, 展示了xaml和相應的後台代碼

示例6-20

<ResourceDictionary x:Class="SimpleSkin.BlueSkin"
    xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
    >
    <Style TargetType="{x:Type Button}">
        <Setter Property="Background" Value="Blue" />
        <Setter Property="Foreground" Value="White" />
    </Style>
</ResourceDictionary>

示例6-21

using System;
using System.Windows;

namespace SimpleSkin {

    public partial class BlueSkin : ResourceDictionary {

         public BlueSkin( ) {
            InitializeComponent( );
        }
    }
}

以上代碼為一個按鈕設置了前景色和背景色。一個更復雜的皮膚應該可以為 更多的類型元素提供樣式,並且提供更多的屬性。更多的皮膚包括一些模板屬性 的設定,從而可以定義控件的外觀。但是即使是在這個簡單的例子中,底層的原 理也都是一樣的。示例6-22展示了一個UI,示例6-23則是這個UI的相應後台代碼 ,允許皮膚的切換。(這個示例假設有2個皮膚類,BlueSkin和GreenSkin,都是 使用示例6-20的技術定義的。)

示例6-22

<Window x:Class="SimpleSkin.Window1" Text="SimpleSkin"
    xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
    xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005">

     <Grid Margin="1">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <RadioButtonList x:Name="radioSkins">
            <TextBlock>Green</TextBlock>
            <TextBlock>Blue</TextBlock>
        </RadioButtonList>

        <Button Grid.Row="1">Hello</Button>
    </Grid>
</Window>

示例6-23

using System;
using System.Windows;
using System.Windows.Controls;

namespace SimpleSkin {

     public partial class Window1 : Window {

        public Window1( ) {
            InitializeComponent( );

             EnsureSkins( );

            radioSkins.SelectionChanged += SkinChanged;
        }

        static ResourceDictionary greenSkin;
        static ResourceDictionary blueSkin;
        static bool resourcesLoaded = false;

         private static void EnsureSkins( ) {
            if (!resourcesLoaded) {
                greenSkin = new GreenSkin( );
                blueSkin = new BlueSkin( );

                 resourcesLoaded = true;
            }
        }

        private void SkinChanged(object o, SelectionChangedEventArgs e) {
            switch (radioSkins.SelectedIndex) {
                case 0:
                    Application.Current.Resources = greenSkin;
                    break;
                case 1:
                    Application.Current.Resources = blueSkin;
                    break;
            }
        }
    }
}

SimpleSkin類的代碼確保了皮膚只創建一次,而且簡單地更換皮膚——通過 設置應用程序資源字典,使之成為選中的皮膚。(第二個皮膚的源GreenSkin, 在這裡沒有顯示出來,看上去和示例6-20相同,只是用綠色取代了藍色。)樣式 和系統資源隨著資源的更換自動反映出來:當更改皮膚的時候更新所有有效的控 件,因此,這就是我們需要的代碼。圖6-5顯示了代碼效果。

圖6-5

這種切換皮膚的方式有一個小障礙。除了使用皮膚資源,在應用程序級別也 存儲了一些資源,那麼這些應用程序資源會在切換皮膚時丟失。現在,唯一的解 決方案是保證每一個皮膚包含一份應用程序級別的資源副本。最好的辦法是將這 些副本保存在一個單獨的類,並將副本和並到資源皮膚中。WPF當前的版本不支 持自動和並資源字典,WPF團隊的成員已經聲明,他們正在考慮更容易的處理辦 法在未來的發布版本中。目前,只能手動處理,正如示例6-24所示。

示例6-24

ResourceDictionary skinResources = new FooSkinResources( );
ResourceDictionary nonSkinAppResources = new DrawingResources( );

foreach (DictionaryEntry de in nonSkinAppResources) {
    skinResources.Add(de.Key, de.Value);
}

如上,你可以將代碼添加到加載資源的方法中。在示例6-23中,你可以在 EnsureSkins方法中和並資源,將blue和green皮膚都和並到 nonSkinAppResources中。

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