淺析Family Show 2.0的動態換膚實現

來源:互聯網
上載者:User

作者:Tony Qu 

前兩天Family Show 2.0終於發布了(有關Family Show的項目資訊大家可以看這裡)。出於興趣,這兩天對這個項目中用到的一些技術作了一些研究。首先吸引我的就是這個動態換膚功能,請看下面兩張圖:

這張是Black Skin的效果


這張是Silver Skin的效果

我們會發現整個視窗風格都變了,很酷吧。。。

我先來介紹一下ResourceDictionary。ResourceDictionary中文譯做資源字典,顧名思義,就是一個用來存放資源的集合。ResourceDictionary元素中可以直接嵌入資源,如下所示:

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

  <SolidColorBrush x:Key="MainBackgroundBrush" Color="#FF202020"/>

  <LinearGradientBrush x:Key="PanelGradientBrush" EndPoint="1,0.5" StartPoint="0,0.5">
    <GradientStop Color="#FF555555" Offset="0"/>
    <GradientStop Color="#FF1C1C1C" Offset="1"/>
  </LinearGradientBrush>

</ResourceDictionary>

也可以切入另一個ResourceDictionary,如下所示:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="Resources\Style1.xaml"/>
    <ResourceDictionary Source="Resources\Style2.xaml"/>
  </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

這裡的MergedDicionaries是關鍵,它會把內嵌資源檔案合并起來,就像在一個資源中一樣,但要注意一點——內嵌資源檔案必須把ResourceDictionary作為根項目。

接下來的一個重點就是動態資源引用。在WPF中資源引用分為動態和靜態兩種,所謂動態資源引用就是一旦資源內容改變就會影響相應的內容,例如Window的背景動態引用了一個SolidColorBrush資源,一旦這個SolidColorBrush改變,那麼背景同時也會改變;而靜態資源引用則是僅在資源第一次使用時載入,所以如果使用的靜態資源引用,即使之後資源的內容變化了,也不會對應用了資源的元素或屬性產生任何影響。由於Family Show要實現的是動態換膚,靜態資源引用恐怕是無能為力了,所以得用動態資源,例如:

<Border x:Name="Header" Background="{DynamicResource BackgroundBrush}" BorderBrush="{DynamicResource BorderBrush}" BorderThickness="1,1,1,0" CornerRadius="5,5,0,0">
      <TextBlock Text="Add a family member" TextWrapping="Wrap" Margin="15,5,10,5" Foreground="{DynamicResource HeaderFontColor}" FontSize="18" VerticalAlignment="Center" FontWeight="Bold" x:Name="HeaderTextBlock"/>
</Border>

這裡的Border.Background動態引用了BackgroundBrush資源Border.BorderBrush則引用了BorderBrush資源,TextBlock.Foreground則引用了HeaderFontColor資源。那麼這些資源分別儲存在哪裡呢?原來它們都儲存在每個Skin的BrushResources.xaml中,如下:

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

  <!-- The Background Brush is used as the background for the Headers and Footers -->
  <SolidColorBrush x:Key="BackgroundBrush" Color="#FF202020"/>

  <!-- The Border Brush is used as the color for most borders -->
  <SolidColorBrush x:Key="BorderBrush" Color="#FF747474"/>

  <SolidColorBrush x:Key="HeaderFontColor" Color="#FFE6E6E6"/>

</ResourceDictionary>

所以,如果大家為找不到這些資源而發愁,這就是答案。

另外,之所以可以在Family Show中直接用{DynamicResource XXX}這樣的形式直接引用資源,還有一個原因,那就是這些資源都被作為了應用程式級資源,讓我們看看App.xaml中的代碼:

<Application
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="Microsoft.FamilyShow.App"
    StartupUri="MainWindow.xaml"
    >
  <Application.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <!-- Use the Black skin by default -->
        <ResourceDictionary Source="Skins\Black\BlackResources.xaml"/>
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </Application.Resources>
</Application>

我們會發現原來預設情況下會把Skins\Black\BlackResources.xaml作為應用程式級資源引入,這也是為什麼我們預設看到的是Black Skin,而不是Silver Skin。這裡也順便提一下,WPF的資源都是有作用範圍的,有應用程式級的資源,也有Window級的資源,還有控制項級的資源,所以在使用一個資源之前一定要先確認是否在它的作用範圍之內。

但這裡只解決了預設的Skin載入,如何在程式運行時實現資源替換呢?答案就是下面這段代碼:        /**//// <summary>
        /// Command handler for ChangeSkinCommand
        /// </summary>
        private void ChangeSkin(object sender, ExecutedRoutedEventArgs e)
        {
            ResourceDictionary rd = new ResourceDictionary();
            rd.MergedDictionaries.Add(Application.LoadComponent(new Uri(e.Parameter as string, UriKind.Relative)) as ResourceDictionary);
            Application.Current.Resources = rd;
          
        }

ChangeSkin其實是一個事件處理常式,對應於ChangeSkin路由事件。(關於路由事件的知識由於超出了這篇文章的範疇,就不做展開了,我可能會在另一篇文章中單獨講解,這裡你只要把它當作一個普通事件來理解就可以了。)這個事件處理常式是在點擊Skin菜單中的功能表項目時觸發的。其實代碼還是比較簡單的——首先建立一個ResourceDictionary,然後把新的資源字典載入進來放入MergedDictionary中,最後把這個資源字典作為當前應用程式的資源。

到此,我想你對Family Show 2.0動態換膚的實現已經理解得差不多了。當然這隻是WPF中換膚的基礎而已,其實WPF換膚不僅僅可以換某個控制項的顏色,還可以換布局、樣式等,這可以讓你的應用程式產生奪人眼球的效果,但由於布局和樣式在WPF中是兩個很大的主題,在本文中無法一一道來,建議大家可以去看看WPF Unleashed的第8章“資源”和第10章“樣式、模板、皮膚和主題”,相信會對理解資源和進階換膚有很大協助。 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.