# WPF自訂元件 Level 1: Style in resource 字訂元件是WPF一項很重要的技術,我從自訂深度幫他定義了多個Level,深度越深可以自訂的東西越多,如果想要很炫麗的元件,除了用別人做好的套件以外,只能自己學習如何深度自訂元件。 最簡單的字訂元件,就是在Resource寫Style,然後在元件上透過指定Style套用 一般設定元件樣式的時候,會這樣寫 ```wpf <TextBlock Text="Custom TextBlock 1" HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="100" Margin="5" Padding="3"/> <TextBlock Text="Custom TextBlock 2" HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="100" Margin="8" Padding="3" Foreground="Red"/> ``` 這樣做的問題就是,如果如果有很多相同的屬性要自訂,將會**重複寫很多的程式碼**,軟體工程師的共同特色就是懶,我們就是不想寫一堆一樣的東西,所以程式碼的**再利用就**顯得無比重要,這時候就來到今天的主題,**Style in resource** ## 區域Resource 先試試把Style寫在小區域的作法 ```wpf <Window ... > <Window.Resources> <Style x:Key="NormalTextBlock" TargetType="TextBlock"> <Setter Property="HorizontalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="Padding" Value="5" /> <Setter Property="MinWidth" Value="100" /> </Style> <Style x:Key="RedTextBlock" TargetType="TextBlock" "{StaticResource NormalTextBlock}"> <Setter Property="Foreground" Value="Red" /> </Style> </Window.Resources> <StackPanel> <TextBlock Text="Custom TextBlock 1" Style="{StaticResource RedTextBlock}" Margin="5" Padding="3" /> <TextBlock Text="Custom TextBlock 2" Style="{StaticResource NormalTextBlock}" Margin="8" /> </StackPanel> <Window/> ``` 自訂了一個名為NormalTextBlock的Style,並在TargetType指定要套用到TextBlock,並添加了兩個TextBlock都共有的4個屬性。 接著基於前面的NormalTextBlock再建立一個RedTextBlock,並且設定文字顏色為紅色,這個Style會有NormalTextBlock的所有屬性,並且加以修改,如果跟NormalTextBlock有重複的屬性,則會**複蓋**過去,以後面的為準。 這樣一來,以後如果要建立多種顏色的TextBlock,都可以基於NormalTextBlock去建立新的Style,然後一層一層疊上去。 ## 依照元件類型套用 或者如果不想寫這麼複雜,也可以不指定Key,寫一個套用到所有TextBlock的Style ```wpf <Window.Resources> <Style TargetType="TextBlock"> <Setter Property="HorizontalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="Padding" Value="5" /> <Setter Property="MinWidth" Value="100" /> </Style> <Style x:Key="RedTextBlock" TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}"> <Setter Property="Foreground" Value="Red" /> </Style> </Window.Resources> ``` 如此一來,但凡沒有指定Style的TextBlock也都會被套用上基本的規則,其中比較特別的是,因為原本的NormalTextBlock現在沒有Key了,所以如果RedTextBlock的BaseOn就必須要特別去設定成`{StaticResource {x:Type TextBlock}}`,不然就會發現他只有紅色,但是卻沒有置中等屬性 ## 套用到全域 ㄟ,flier268,如果我這個Style要在整個App都用怎麼辦?每一個Window都寫貼一遍嗎? flier268: 你貼阿,我才沒這麼勤勞 還是那句話,我很懶,我懶得做重工的事情,可以一次搞定的事情絕對不想做第二次 打開`app.xaml`,然後改成這樣 ```wpf <Application x:Class="CustomStyleTest.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" StartupUri="MainWindow.xaml"> <Application.Resources> <Style TargetType="TextBlock"> <Setter Property="HorizontalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="Padding" Value="5" /> <Setter Property="MinWidth" Value="100" /> </Style> <Style x:Key="RedTextBlock" TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}"> <Setter Property="Foreground" Value="Red" /> </Style> </Application.Resources> </Application> ``` WPF在預設情況下,都是基於Application(目前不確定有沒有辦法改變這件事情,也許真的就沒有),所以要套用在所有地方,就寫在這裡(或者用命名空間指定是哪個Resource也行,如果有機會再講),一樣,有簡單作法跟複雜作法。 ## 超多Style的救星: ResourceDictionary 簡單的做法就是像上述的程式碼一樣,把Style直接寫在Resource裡面,但是,想像一下,如果我在app.xaml自訂各種元件、各種款式的狀況吧,這樣app.xaml寫個幾百行都是很正常的事情,工程師除了懶以外還有另一種病,就是不喜歡找不到東西在哪,改個東西在成百上千行的文件裡面找到某一行,就算可以使用搜尋的,但想想還是累,這時,另一個功能`ResourceDictionary`就出現了。 要做的事情有兩件事 1. 依照你的分類方法,把同類型的Style移到單獨的Dictionary 建立TextBlockStyle.xaml(在加入項目那邊選擇`資源字典`) ```wpf <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <Style TargetType="TextBlock"> <Setter Property="HorizontalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="Padding" Value="5" /> <Setter Property="MinWidth" Value="100" /> </Style> <Style x:Key="RedTextBlock" TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}"> <Setter Property="Foreground" Value="Red" /> </Style> </ResourceDictionary> ``` 2. 在app.xaml加入那個Dictionary 把原本寫Style的地方改成ResourceDictionary,像是這樣: ```wpf <Application x:Class="CustomStyleTest.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" StartupUri="MainWindow.xaml"> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="TextBlockStyle.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> </Application> ``` 順帶一提,這邊的範例只是簡單介紹,實際使用會分得更多層,這樣才有較大的彈性。 ## 優缺點 優點:簡單易學,可重複使用 缺點:無法深度字訂元件樣式,只能在現有參數上設定 下一章:[WPF自訂元件 Level 2: Trigger](https://hackmd.io/@flier268/HJXBiQR6Y) ###### tags: `C#` `WPF` `WPF字訂元件`
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up