<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      深入WPF--Style

      Style 用來在類型的不同實例之間共享屬性、資源和事件處理程序,您可以將 Style 看作是將一組屬性值應用到多個元素的捷徑。

        這是MSDN上對Style的描述,翻譯的還算中規中矩。Style(樣式),簡單來說,就是一種對屬性值的批處理,類似于Html的CSS,可以快速的設置一系列屬性值到UI元素。

      示例

        一個最簡單的Style的例子:

         1: <Window>
         2:     <Grid>
         3:         <Grid.Resources>
         4:             <Style TargetType="{x:Type Button}" x:Key="ButtonStyle">
         5:                 <Setter Property="Height" Value="22"/>
         6:                 <Setter Property="Width" Value="60"/>
         7:             </Style>
         8:         </Grid.Resources>
         9:         <Button Content="Button" Style="{StaticResource ButtonStyle}"/>
        10:         <Button Content="Button" Style="{StaticResource ButtonStyle}" Margin="156,144,286,145" />
        11:     </Grid>
        12: </Window>

        關于Resources的知識,請參見MSDN,這里創建了一個目標類型為Button的ButtonStyle,兩個Button使用靜態資源(StaticResource)的查找方式來找到這個Style。Style中定義了Button的高度(Height)和寬度(Width),當使用了這個Style后,兩個Button無需手動設置,即可自動設置它們的高度和寬度為ButtonStyle的預設值22和60。

        Style作為屬性,資源,事件的批處理,它提供了一種捷徑來對控件進行快速設置,使用Style的好處有二:

      1. 把一些控件的通用設置抽出來變成Style,使這些控件具有統一的風格,修改Style中的屬性值可以方便的作用在所有應用該Style的控件上。
      2. 可以對同一類型控件定義多個Style,通過替換Style來方便的更改控件的樣式。

      Style的元素

        上面Style的例子中,Style內部使用了Setter來定義控件屬性的預設值,Style不僅支持對屬性的批處理,也可以共享資源和事件處理,如:

         1: <Window>
         2:     <Window.Resources>
         3:         <Style TargetType="{x:Type Button}" x:Key="ButtonStyle">
         4:             <Style.Resources>
         5:                 <SolidColorBrush x:Key="brush" Color="Yellow"/>
         6:             </Style.Resources>
         7:             <Setter Property="Height" Value="22"/>
         8:             <Setter Property="Width" Value="60"/>
         9:             <EventSetter Event="Loaded" Handler="Button_Loaded"/>
        10:         </Style>
        11:     </Window.Resources>
        12:     <x:Code>
        13:         <![CDATA[
        14:             void Button_Loaded(object sender, RoutedEventArgs e)
        15:             {
        16:                 MessageBox.Show((sender as Button).Name + " Loaded");
        17:             }
        18:         ]]>
        19:     </x:Code>
        20:     <Grid>
        21:         <Button x:Name="button1" Style="{StaticResource ButtonStyle}" Background="{DynamicResource brush}"/>
        22:         <Button x:Name="button2" Style="{StaticResource ButtonStyle}" Background="{DynamicResource brush}" Margin="156,144,286,145" />
        23:     </Grid>
        24: </Window>

        Style中定義了資源SolidColorBrush,定義了屬性Height和Width,以及使用了EventSetter來定義了Loaded事件的處理。

      Trigger

        Style使用了Setter和EventSetter來分別設置控件的屬性和事件處理,Setter這個單詞的含義是設置。Style在設計好了這兩種設置后,又引入了更先進的思路:條件設置。

        對于單純的Setter:<Setter Property=”Height” Value=”22”>來說,含義淺顯易懂:設置高度為22。條件設置的含義是,在某種條件下,去設置某個對象的某個值。

        WPF引入了Trigger(觸發器)來觸發這個條件,它的寫法是:

         1: <Style TargetType="{x:Type Button}" x:Key="ButtonStyle">
         2:     <Setter Property="Width" Value="60"/>
         3:     <Style.Triggers>
         4:         <Trigger Property="IsMouseOver" Value="True">
         5:             <Setter Property="Width" Value="80"/>
         6:         </Trigger>
         7:     </Style.Triggers>
         8: </Style>

        這里Trigger的含義是,在Button的IsMouseOver屬性被設置為True的條件下,設置Button的寬度(Width)為80。

        在Style中,不需要指定Setter作用的對象(TargetName),默認作用的對象就是使用該Style的控件。Trigger,作為觸發器,當觸發時設置寬度為80,當IsMouseOver屬性為False,也就是觸發條件失效時,寬度回到默認Setter的設置值60。

        WPF定義了五種Trigger來作為觸發條件,分別是:Trigger,DataTrigger,MultiTrigger,MultiDataTrigger,EventTrigger,他們的觸發條件分別是:

      1. Trigger:以控件的屬性作為觸發條件,如前面的IsMouseOver為True的時候觸發。
      2. DataTrigger:以控件DataContext的屬性作為觸發條件。
      3. MultiTrigger:以控件的多個屬性作為觸發條件。
      4. MultiDataTrigger:以控件DataContext的多個屬性作為觸發條件。
      5. EventTrigger:以RoutedEvent作為觸發條件,當指定的路由事件Raise時觸發。

        關于這5種Trigger的具體使用,請參見MSDN,這里就不詳細介紹了。

      Implicit Style

        上面的例子中,都是使用StaticResource來設置Style的,當然,你也可以使用DynamicResource來設置Style。這兩種方式都需要你在XAML或者后臺代碼中手動注明,為了使用方便,WPF提出了隱式(Implicit) Style的方式允許自動設置Style到控件,如:

         1: <Window>
         2:     <Grid>
         3:         <Grid.Resources>
         4:             <Style TargetType="{x:Type Button}">
         5:                 <Setter Property="Height" Value="22"/>
         6:                 <Setter Property="Width" Value="60"/>
         7:             </Style>
         8:         </Grid.Resources>
         9:         <Button x:Name="button1" Style="{x:Null}"/>
        10:         <Button x:Name="button2" Margin="156,144,286,145" />
        11:         <Button x:Name="button3" Margin="196,144,0,145" />
        12:     </Grid>
        13: </Window>

        在Gird的Resource中定義Style時,沒有給Style起名字(Key),這個Style會自動應用在Grid的所有子Button中,如果像button1一樣在Button中顯式定義了Style(這里設置了一個空值Null),那么這種隱式(Implicit)的Style會不起作用。

      深入Style

        Style是一個不錯的概念,作為一個Presentation的框架,把UI對象的結構,樣式和行為分離這是一種很好的設計。Style也比較容易上手,像它的隱式(Implicit)Style的設計也是水到渠成的想法,但實際使用中也會出現一些問題。這些問題在WPF中也會經常遇見:概念不錯,描述簡單,前景美好,Bug稀奇古怪,要把這些問題說清楚,就要從根本來看,Style是個什么東西?

        按照通常的想法,Style應該類似于一個Dictionary<string, object> setters,預存了屬性的名字和預設值,然后作用到UI對象上。WPF在Style處的想法很多,圍繞著幾個關鍵技術也加入了很多功能,詳細的介紹一下:

      Style & Dependency Property

        Dependency Property(簡稱DP)是WPF的核心,Style就是基于Dependency Property的,關于DP的內幕,請參見深入WPF--依賴屬性。Style中的Setter就是作用在DP上的,如果你在控件中定義了一個CLR屬性,Style是不能設置的。Dependency Property設計的精髓在于把字段的存取和對象(Dependency Object)剝離開,一個屬性值內部用多個字段來存儲,根據取值條件的優先級來決定當前屬性應該取哪個字段。

        Dependency Property取值條件的優先級是(從上到下優先級從低到高):

         1: public enum BaseValueSource
         2: {
         3:     Unknown,
         4:     Default,
         5:     Inherited,
         6:     DefaultStyle,
         7:     DefaultStyleTrigger,
         8:     Style,
         9:     TemplateTrigger,
        10:     StyleTrigger,
        11:     ImplicitStyleReference,
        12:     ParentTemplate,
        13:     ParentTemplateTrigger,
        14:     Local
        15: }

        對于一個具體例子來說:

         1: <Window>
         2:     <Window.Resources>
         3:         <Style TargetType="{x:Type Button}" x:Key="ButtonStyle">
         4:             <Setter Property="Width" Value="60"/>
         5:             <Style.Triggers>
         6:                 <Trigger Property="IsMouseOver" Value="True">
         7:                     <Setter Property="Width" Value="80"/>
         8:                 </Trigger>
         9:             </Style.Triggers>
        10:         </Style>
        11:     </Window.Resources>
        12:     <Grid>
        13:         <Button x:Name="button1" Style="{StaticResource ButtonStyle}" Background="{DynamicResource brush}" Width="20"/>
        14:     </Grid>
        15: </Window>

        第4行用Style的Setter設置Width=60,這個優先級是Style;第6行當IsMouseOver為True時設置Width=80,這個優先級是StyleTrigger;第13行使用Style的Button定義Width=20,這個優先級是Local。Local具有最高的優先級,所以即使鼠標移到Button上,第6行的Trigger也會因為優先級不夠高而不起作用。如果去掉了第13行中的Width=20,那么鼠標移到Button上時Width會變為80,鼠標移開后會回到第4行的設置的60來。

      Style & FrameworkElement

        Style作為一個屬性定義在FrameworkElement上,所有繼承自FrameworkElement的控件都可以使用Style。FrameworkElement定義了多個Style:Style,ThemeStyle,FocusVisualStyle:

      1. FocusVisualStyle:是當控件獲得鍵盤焦點時,顯示在外面的一個虛線框,這個Style并沒有直接作用在對應的FrameworkElement上,而是當控件獲得鍵盤焦點時使用AdornLayer創建了一個新的Control,然后再這個Control上使用FocusVisualStyle,再把它遮蓋在對應的FrameworkElement上形成一個虛線框的效果。
      2. Style:就是我們前面一直設置的Style。
      3. ThemeStyle:這里引入了一個Theme的概念,具體來談一下它。

        Windows定了很多Theme(主題),你可以在控制面板中切換Theme,如圖:

       

      Theme

        最上面的兩排都屬于Aero主題,當從Aero主題切換到Windows Classic主題后,任務欄,窗口以及窗口內的控件外觀都會發生變化。為了更好的切換主題,WPF引入了ThemeStyle這個概念。當我們使用VS2010的模板生成一個自定義控件(Custom Control)后,會自動添加一個Themes的文件夾以及一個Generic.xaml的文件,如圖:

      generic

        這里的Aero.NormalColor.xaml是手動添加的,先略去不談,來談談控件(Control)的默認樣式。

        WPF默認提供了很多控件,Button,ListBox,TabControl等等,我們使用這些控件時,是沒有指定它的樣式(Style)的,WPF為我們提供了默認Style,這個默認Style是與Windows主題相關的。比如我們切換Windows的主題從Aero到Classic,WPF窗口里的控件外觀也會發生變化。這些默認的Style是以ResourceDictionary的形式保存在PresentationFramework.Aero.dll,PresentationFramework.Classic.dll等dll中的,這里的命名規則是:程序集名稱+Theme名稱+.dll。

        那么WPF又是如何根據Windows的Theme找到對應的ThemeStyle呢?WPF提出了ThemeInfo這個Attribute來指定Theme信息。ThemeInfo一般定義在Properties/AssemblyInfo.cs中,如:

         1: [assembly: ThemeInfo(
         2:     ResourceDictionaryLocation.SourceAssembly,     
         3:     ResourceDictionaryLocation.SourceAssembly)
         4: )]

        ThemeInfo有兩個參數,第一個參數指的是ThemeResource,第二個參數指的是GenericResource,它們的類型是ResourceDictionaryLocation:

         1: public enum ResourceDictionaryLocation
         2: {
         3:     None = 0,
         4:     SourceAssembly = 1,
         5:     ExternalAssembly = 2,
         6: }

        ResourceDictionaryLocation的None指不存在對應的Resource,SourceAssembly指該程序集(Assembly)中存在對應的Resource,ExternalAssembly指對應的Resource保存在外部的程序集(Assembly)中,這個外部程序集的查找規則就是我們前面看到的:程序集名稱+Theme名稱+.dll。

        對于一個控件,無論是系統自帶的控件還是我們自定義的控件,WPF啟動時都會通過當前Windows系統的Theme查找它對應的ThemeStyle。這個查找規則是:

      1. 先通過控件的類型(Type)找到它對應的程序集(Assembly),然后獲取程序集中的ThemeInfo,看看它的ThemeResource和GenericResource在哪里。如果ThemeResource的值不是None,系統會讀取到ThemeResource對應的ResourceDictionary,在這個ResourceDictionary中查找是否定義了TargetType={x:Type 控件類型},如果有,把控件的ThemeStyle指定為這個Style。
      2. 如果第一步的查找失敗,那么GenericResource派上用場,Generic這個詞表示一般。WPF會查看ThemeInfo的第二個參數GenericResource來查找它的ThemeStyle,查找規則同第一步,如果查找成功,把這個Style指定為控件的ThemeStyle。

        任意一個控件,如果不顯式指定它的Style,并且查不到默認的ThemeStyle,這個控件是沒有外觀的。為了編程方便,當我們使用VS添加自定義控件時,VS默認幫我們生成了Generic.xaml,如果我們希望自定義的控件也要支持系統的Theme變化,可以在Themes這個文件夾下加入對應的ResourceDictionary,比如上面的Aero.NormalColor.xaml,并且指定程序集ThemeInfo的第一個參數為SourceAssembly,表明該程序集支持系統Theme變化并且對應的資源文件在該程序集中。當然,ResourceDictionary一定要放在Themes文件夾下,因為WPF查找ResourceDictionary時使用的是類似:

         1: string relativePackUriForResources = "/" +
         2:         themeAssemblyName.FullName +
         3:         ";component/themes/" +
         4:         themeName + "." +
         5:         colorScheme + ".xaml";

      這樣的方法。

      Style & ResourceDictionary

        前面提到了很多次ResourceDictionary,關于WPF的Resource系統,以后再來細談。WPF的Resource系統使用ResourceDictionary來儲存Resource,ResourceDictionary,顧名思義,也是一個Dictionary,既然是Dictionary,就是按鍵/值對來存儲的。我們最前面在Window的Resource中創建Style時,指定了Style對應的鍵值(x:Key),后面又用StaticResource來引用這個鍵值。

        如果在ResourceDictionary中添加一個對象Button,不指定它的鍵值(x:Key),是不能通過編譯的。我們前面介紹的隱式(Implicit)Style,只指定了一個TargetType={x:Type  類型},并沒有指定鍵值,為什么它可以通過編譯呢?

        對于在ResourceDictionary中添加Style,如果我們沒有指定鍵值(x:Key),WPF會默認幫我們生成鍵值,這個鍵值不是一個String,而是一個類型object(具體來說是Type實例),也就是說相當于:

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

      后面的x:Key可以省略掉。

        Appliation以及FrameworkElement類都定義了Resources屬性,內部都持有一個ResourceDictionary,Resource查找遵循的最基本原則是就近原則,如:

         1: <Window>
         2:     <Window.Resources>
         3:         <Style TargetType="{x:Type Button}">
         4:             <Setter Property="Background" Value="Yellow"/>
         5:         </Style>
         6:         <Style TargetType="{x:Type ToggleButton}" x:Key="toggleBtnStyle">
         7:             <Setter Property="Background" Value="Red"/>
         8:         </Style>
         9:     </Window.Resources>
        10:     <StackPanel>
        11:         <StackPanel.Resources>
        12:             <Style TargetType="{x:Type Button}">
        13:                 <Setter Property="Background" Value="Blue"/>
        14:             </Style>
        15:             <Style TargetType="{x:Type ToggleButton}" x:Key="toggleBtnStyle">
        16:                 <Setter Property="Background" Value="Green"/>
        17:             </Style>
        18:         </StackPanel.Resources>
        19:         <ToggleButton Width="80" Height="20" Style="{DynamicResource toggleBtnStyle}"/>
        20:         <Button Width="80" Height="20"  Content="button2" Click="Button_Click"/>
        21:     </StackPanel>
        22: </Window>

        Window和StackPanel的Resources中都分別定義了toggleBtnStyle以及隱式Style(Button),根據就近原則,StackPanel內部的ToggleButton和Button會應用StackPanel的Resource而不會使用Window的。

      Style Merge

        這里要提到本篇的重點也是不被人注意卻經常出錯的地方,Style的合并(Merge)。

        前面提到了很多Style,ThemeStyle,Style,隱式Style。我們提過,Style相當于一個屬性值的批處理,那么對于一個屬性,只能有一個預設值而不能多個,這些Style在運行時要進行合并,然后作用在FrameworkElement上。

        Style的合并,要分兩步進行:

      1. 找到所有Style。
      2. 確定Style的優先級,根據優先級來合并Style。

        以Button來說:

      1. 如果當前Windows的Theme是Aero,啟動后會從PresentationFramework.Aero.dll中找到對應的ThemeStyle。
      2. 如果在Button上使用StaticResource或者DynamicResource指定了Style,會通過鍵值在Resource系統中找到對應的Style。
      3. 如果沒有在Button上顯式指定Style,會通過Resource系統查找隱式Style(x:Type Button)。
      4. 第二步和第三步是排他的,這兩步只能確定一個Style,然后把這個Style和ThemeStyle進行合并(Merge)得到Button最終的效果。

        先從合并來說,顯式或者隱式Style的優先級是高于ThemeStyle的,如果Style和ThemeStyle的Setter中都對同一屬性進行了預設,那么會取Style里面的Setter而忽略ThemeStyle。這里比較特殊的是EventSetter,EventSetter使用的是RoutedEvent,如果兩個Style的EventSetter對同一個RoutedEvent進行了設置,兩個都會注冊到RoutedEvent上。

        前面看到,顯式和隱式Style是排他的,兩者只能取一,在實際項目中,在全局定義好Button的基本樣式,然后具體使用上再根據基本樣式做一些特殊處理,這種需求是很常見的。為了解決這種需求,Style提出了BasedOn屬性,來表示繼承關系,如:

         1: <Window>
         2:     <Window.Resources>
         3:         <Style TargetType="{x:Type Button}">
         4:             <Setter Property="Width" Value="80"/>
         5:             <Setter Property="Height" Value="20"/>
         6:             <EventSetter Event="Click" Handler="btnBase_Click"/>
         7:         </Style>
         8:         <Style TargetType="{x:Type ButtonBase}" x:Key="toggleBtnStyle">
         9:             <Setter Property="Width" Value="80"/>
        10:             <Setter Property="Height" Value="20"/>
        11:             <Setter Property="Background" Value="Red"/>
        12:         </Style>
        13:     </Window.Resources>
        14:     <StackPanel>
        15:         <StackPanel.Resources>
        16:             <Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
        17:                 <Setter Property="Background" Value="Blue"/>
        18:                 <EventSetter Event="Click" Handler="btn_Click"/>
        19:             </Style>
        20:             <Style TargetType="{x:Type ToggleButton}" x:Key="toggleBtnStyle" BasedOn="{StaticResource toggleBtnStyle}">
        21:                 <Setter Property="Background" Value="Green"/>
        22:             </Style>
        23:         </StackPanel.Resources>
        24:         <ToggleButton Style="{DynamicResource toggleBtnStyle}"/>
        25:         <Button Content="button2"/>
        26:     </StackPanel>
        27: </Window>

        為了更清晰的解釋,給出了一個不太常見的例子。第16行創建了一個隱式Style(Button),它的BasedOn屬性仍然是隱式Style(Button),Resource系統會向上查找找到Window的Resorces中的隱式Style(Button),然后把兩者合并。對于同一個ResourceDictionary,是不允許有重復鍵值的,StackPanel和Window各有各自的ResourceDictionary,他們的鍵值不受干擾,查找時會通過就近原則來找到優先級最高的Resource。第20行ToggleButton的例子和Button是一樣的,只是它查找到的第8行toggleBtnStyle的TargetStyle是ButtonBase,ButtonBase是ToggleButton的基類,BasedOn屬性也可以作用。

        WPF的Style機制是一個密封(Seal)機制,它的書寫方式很靈活,可以支持合并等,當最后合并后,Style就被密封(Seal),內部的Setter等不允許再被修改。這種密封的設計有它的道理,但在Style的動態性上就稍顯不足。

        以自定義控件為例,自定義一個Button,名字叫MyButton,它繼承自Button,在自定義控件中,經常可以看到這樣的代碼:

         1: static MyButton()
         2: {
         3:     DefaultStyleKeyProperty.OverrideMetadata(typeof(MyButton), new FrameworkPropertyMetadata(typeof(MyButton)));
         4: }

        這里出現了DefaultStyle,這個是WPF對ThemeStyle的另一個說法,ThemeStyle就是用來確定默認的Style的,后來包括BaseValueSource中也使用了DefaultStyle來表示ThemeStyle。在MyButton的靜態函數中重載DefaultStyleKeyProperty內部Metadata的含義是告訴WPF系統,查找MyButton的ThemeStyle使用的鍵值從{x:Type Button}被改成了{x:Type MyButton}。

        如果像上述代碼一樣修改了DefaultStyleKeyProperty,那么需要我們在Themes/Generic.xaml中定義好MyButton的默認(Theme)Style,否則MyButton是沒有外觀的,因為查找ThemeStyle的鍵值已經被修改,PresentationFramework.Aero.dll等dll中是沒有定義{x:Type MyButton}的。

        前面是關于ThemeStyle的用法,那么回到隱式Style上來,如果我們在Application的Resources中定義了Button的隱式Style(TargetType={x:Type Button}),即使沒有顯式設置MyButton的Style,所有的MyButton控件也不會使用這個隱式Style的。需要你在Application的Resources中,在定義Button隱式Style的下面定義

         1: <Style TargetType="{x:Type local:MyButton}" BasedOn="{StaticResource {x:Type Button}}"/>

        這里就回到Style的合并(Merge)上來了,Style的Merge是很基本(很傻)的合并(Merge),它不具備Auto性。具體來說,就是:

      1. 基類控件的隱式Style不會作用到派生類控件上。
      2. 像前面在Window和StackPanel中分別定義了隱式Style(Button),這兩個隱式Style不會智能合并后再作用到Button上,而是通過就近原則只選其一。
      3. Style的BasedOn屬性只支持StaticResource方式引用,因為Style繼承自DispatcherObject而不是DependencyObject,DynamicResource只支持DP。

        這些問題都需要通過Style的BasedOn來解決,因為BasedOn用的是靜態引用(StaticResource),當隱式Style發生變化時就有麻煩了。

      換膚

        UI程序的換膚是很炫的玩意,換膚分兩種:1,更換整個控件的Style;2,更換Style中的顏色畫刷(Brush)。后者的實現很簡單,定義好顏色畫刷的資源文件(ResourceDictionary),使用畫刷的時候使用DynamicResource綁定,換膚的時候替換畫刷的資源文件就可以了。

        很多公司都有自己皮膚庫,這些皮膚庫一般都是隱式的Style,定義了所有控件的隱式Style,使用時把這個皮膚資源Merge到Application的Resources中。換膚時把舊的皮膚資源從Application的Resources中刪除,替換成新的皮膚資源ResourceDictionary。

        這種做法很好理解,但是碰到Style的BasedOn屬性就不起作用了,BasedOn屬性使用是StaticResource,是靜態的一次性的。新的皮膚庫被添加到Application資源文件后,如果在Application的資源文件中已經定義過<Style TargetType=“{x:Type Button}” BasedOn=“{StaticResource {x:Type Button}}”/>這樣隱式的Style,控件是不會更新皮膚的。如果有這方面的需求,需要手動合并(Merge)Style來解決問題,類似:

         1: public static void Merge(this Style style, Style otherStyle)
         2: {
         3:     foreach (SetterBase currentSetter in otherStyle.Setters)
         4:     {
         5:         style.Setters.Add(currentSetter);
         6:     }
         7:  
         8:     foreach (TriggerBase currentTrigger in otherStyle.Triggers)
         9:     {
        10:         style.Triggers.Add(currentTrigger);
        11:     }
        12:  
        13:     foreach (object key in otherStyle.Resources.Keys)
        14:     {
        15:         style.Resources[key] = otherStyle.Resources[key];
        16:     }
        17: }

        這里還需要加上一些條件判斷,以及決定是否要遞歸合并otherStyle的BasedOn,回到前面,程序需要使用DynamicResource來監聽Application資源中隱式Style的變化,用一個附加屬性來解決:

         1: public static readonly DependencyProperty AutoMergeStyleProperty =
         2:     DependencyProperty.RegisterAttached("AutoMergeStyle", typeof(Type), typeof(Behavior),
         3:         new FrameworkPropertyMetadata((Type)null,
         4:             new PropertyChangedCallback(OnAutoMergeStyleChanged)));
         5:  
         6: private static void OnAutoMergeStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
         7: {
         8:     if (e.OldValue == e.NewValue)
         9:     {
        10:         return;
        11:     }
        12:  
        13:     FrameworkElement control = d as FrameworkElement;
        14:     if (control == null)
        15:     {
        16:         throw new NotSupportedException("AutoMergeStyle can only used in FrameworkElement");
        17:     }
        18:  
        19:     Type type = e.NewValue as Type;
        20:     if (type != null)
        21:     {
        22:         control.SetResourceReference(Behavior.BaseOnStyleProperty, type);
        23:     }
        24:     else
        25:     {
        26:         control.ClearValue(Behavior.BaseOnStyleProperty);
        27:     }
        28: }

        SetResourceReference是XAML中DynamicResource的代碼表示,相當于Behavior.BaseOnStyle={DynamicResource type}。對控件使用SetResourceReference,監聽的鍵值是type,監聽的屬性是一個我們自定義的附加屬性BaseOnStyleProperty。當換膚替換Application的資源文件時,BaseOnStyle屬性被更新,在BaseOnStyleProperty的Changed事件中可以讀取控件的Style屬性和新的ThemeStyle,調用Merge方法Merge兩者然后再設置到控件的Style屬性上。

      總結

        WPF中Style的設計中規中矩,把UI對象樣式和結構分離是它的最初想法,其中也加入了Trigger等一些好的設計,但在使用中還是會出現一些問題,它本身也不是那么智能完美。希望朋友們都能從內到外的看待Style,更好的玩轉它。

      閑話

        這個深入WPF系列也寫了好幾篇了,比起用嘴上白話一通,寫文章需要更多的耐心和細致。講解有很多境界:把簡單的東西講復雜;把復雜的東西講復雜;把復雜的東西講簡單;把復雜的東西講簡單,而且還有詩情哲理。我達不到那么高的境界,希望能做到直接不回避的把技術主線講清楚,也希望能更多的聽到朋友們的反饋,我會繼續補充,爭取把這個系列寫好。

        謝謝支持,謝謝您頂一下。 ^_^

       

       

      本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。

      posted @ 2011-08-01 12:07  周永恒  閱讀(57390)  評論(32)    收藏  舉報
      主站蜘蛛池模板: 亚洲精品在线少妇内射| 日韩一区二区三区精品区| 五月婷之久久综合丝袜美腿| 日韩有码中文字幕av| 亚洲老妇女亚洲老熟女久| 青青青爽在线视频观看| 久久国产精品成人影院| 亚洲综合91社区精品福利| 国产精品蜜臀av在线一区| 精品伊人久久久香线蕉| 国产午夜精品福利视频| 国产成人理论在线视频观看| 亚洲国产日韩伦中文字幕| 国产农村乱人伦精品视频| 办公室强奷漂亮少妇同事| 日日噜噜噜夜夜爽爽狠狠视频| 2018年亚洲欧美在线v| 亚洲国产精品一二三四五| 又大又紧又粉嫩18p少妇| 国产免费网站看v片元遮挡| 中文字幕日韩区二区三区| 中文字幕亚洲高清在线一区| 中文字幕亚洲日韩无线码| 国产精欧美一区二区三区| 亚洲欧美牲交| 美女裸体黄网站18禁止免费下载 | 亚洲精品一区二区五月天| 久久se精品一区二区三区| 国产精品成人免费视频网站京东| 激情综合网激情五月激情| 久久99精品久久久久麻豆 | 亚洲午夜无码久久久久蜜臀av| 色五月丁香六月欧美综合| 亚洲日本韩国欧美云霸高清| 熟妇激情一区二区三区| 夜夜爽妓女8888888视频| 日本xxxx色视频在线播放| 国产免费无遮挡吃奶视频| 久热在线中文字幕色999舞| 亚洲一区二区三区自拍偷拍 | 青草青草久热精品视频在线观看|