How to create a style for a control (WPF .NET)
With Windows Presentation Foundation (WPF), you can customize an existing control's appearance with your own reusable style. Styles can be applied globally to your app, windows and pages, or directly to controls.
Create a style
You can think of a Style as a convenient way to apply a set of property values to one or more elements. You can use a style on any element that derives from FrameworkElement or FrameworkContentElement such as a Window or a Button.
The most common way to declare a style is as a resource in the Resources
section in a XAML file. Because styles are resources, they obey the same scoping rules that apply to all resources. Put simply, where you declare a style affects where the style can be applied. For example, if you declare the style in the root element of your app definition XAML file, the style can be used anywhere in your app.
<Application x:Class="IntroToStylingAndTemplating.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
StartupUri="WindowExplicitStyle.xaml">
<Application.Resources>
<ResourceDictionary>
<Style x:Key="Header1" TargetType="TextBlock">
<Setter Property="FontSize" Value="15" />
<Setter Property="FontWeight" Value="ExtraBold" />
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
If you declare the style in one of the app's XAML files, the style can be used only in that XAML file. For more information about scoping rules for resources, see Overview of XAML resources.
<Window x:Class="IntroToStylingAndTemplating.WindowSingleResource"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
mc:Ignorable="d"
Title="WindowSingleResource" Height="450" Width="800">
<Window.Resources>
<Style x:Key="Header1" TargetType="TextBlock">
<Setter Property="FontSize" Value="15" />
<Setter Property="FontWeight" Value="ExtraBold" />
</Style>
</Window.Resources>
<Grid />
</Window>
A style is made up of <Setter>
child elements that set properties on the elements the style is applied to. In the example above, notice that the style is set to apply to TextBlock
types through the TargetType
attribute. The style will set the FontSize to 15
and the FontWeight to ExtraBold
. Add a <Setter>
for each property the style changes.
Apply a style implicitly
A Style is a convenient way to apply a set of property values to more than one element. For example, consider the following TextBlock elements and their default appearance in a window.
<StackPanel>
<TextBlock>My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>
You can change the default appearance by setting properties, such as FontSize and FontFamily, on each TextBlock element directly. However, if you want your TextBlock elements to share some properties, you can create a Style in the Resources
section of your XAML file, as shown here.
<Window.Resources>
<!--A Style that affects all TextBlocks-->
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Comic Sans MS"/>
<Setter Property="FontSize" Value="14"/>
</Style>
</Window.Resources>
When you set the TargetType of your style to the TextBlock type and omit the x:Key
attribute, the style is applied to all the TextBlock elements scoped to the style, which is generally the XAML file itself.
Now the TextBlock elements appear as follows.
Apply a style explicitly
If you add an x:Key
attribute with value to the style, the style is no longer implicitly applied to all elements of TargetType. Only elements that explicitly reference the style will have the style applied to them.
Here is the style from the previous section, but declared with the x:Key
attribute.
<Window.Resources>
<Style x:Key="TitleText" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Comic Sans MS"/>
<Setter Property="FontSize" Value="14"/>
</Style>
</Window.Resources>
To apply the style, set the Style property on the element to the x:Key
value, using a StaticResource markup extension, as shown here.
<StackPanel>
<TextBlock Style="{StaticResource TitleText}">My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>
Notice that the first TextBlock element has the style applied to it while the second TextBlock element remains unchanged. The implicit style from the previous section was changed to a style that declared the x:Key
attribute, meaning, the only element affected by the style is the one that referenced the style directly.
Once a style is applied, explicitly or implicitly, it becomes sealed and can't be changed. If you want to change a style that has been applied, create a new style to replace the existing one. For more information, see the IsSealed property.
You can create an object that chooses a style to apply based on custom logic. For an example, see the example provided for the StyleSelector class.
Apply a style programmatically
To assign a named style to an element programmatically, get the style from the resources collection and assign it to the element's Style property. The items in a resources collection are of type Object. Therefore, you must cast the retrieved style to a System.Windows.Style before assigning it to the Style
property. For example, the following code sets the style of a TextBlock
named textblock1
to the defined style TitleText
.
textblock1.Style = (Style)Resources["TitleText"];
textblock1.Style = CType(Resources("TitleText"), Windows.Style)
Extend a style
Perhaps you want your two TextBlock elements to share some property values, such as the FontFamily and the centered HorizontalAlignment. But you also want the text My Pictures to have some additional properties. You can do that by creating a new style that is based on the first style, as shown here.
<Window.Resources>
<!-- .... other resources .... -->
<!--A Style that affects all TextBlocks-->
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Comic Sans MS"/>
<Setter Property="FontSize" Value="14"/>
</Style>
<!--A Style that extends the previous TextBlock Style with an x:Key of TitleText-->
<Style BasedOn="{StaticResource {x:Type TextBlock}}"
TargetType="TextBlock"
x:Key="TitleText">
<Setter Property="FontSize" Value="26"/>
<Setter Property="Foreground">
<Setter.Value>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.0" Color="#90DDDD" />
<GradientStop Offset="1.0" Color="#5BFFFF" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
Then, apply the style to a TextBlock
.
<StackPanel>
<TextBlock Style="{StaticResource TitleText}" Name="textblock1">My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>
This TextBlock
style is now centered, uses a Comic Sans MS
font with a size of 26
, and the foreground color set to the LinearGradientBrush shown in the example. Notice that it overrides the FontSize value of the base style. If there's more than one Setter pointing to the same property in a Style, the Setter
that is declared last takes precedence.
The following shows what the TextBlock elements now look like:
This TitleText
style extends the style that has been created for the TextBlock type, referenced with BasedOn="{StaticResource {x:Type TextBlock}}"
. You can also extend a style that has an x:Key
by using the x:Key
of the style. For example, if there was a style named Header1
and you wanted to extend that style, you would use BasedOn="{StaticResource Header1}"
.
Relationship of the TargetType property and the x:Key attribute
As previously shown, setting the TargetType property to TextBlock
without assigning the style an x:Key
causes the style to be applied to all TextBlock elements. In this case, the x:Key
is implicitly set to {x:Type TextBlock}
. This means that if you explicitly set the x:Key
value to anything other than {x:Type TextBlock}
, the Style isn't applied to all TextBlock
elements automatically. Instead, you must apply the style (by using the x:Key
value) to the TextBlock
elements explicitly. If your style is in the resources section and you don't set the TargetType
property on your style, then you must set the x:Key
attribute.
In addition to providing a default value for the x:Key
, the TargetType
property specifies the type to which setter properties apply. If you don't specify a TargetType
, you must qualify the properties in your Setter objects with a class name by using the syntax Property="ClassName.Property"
. For example, instead of setting Property="FontSize"
, you must set Property to "TextBlock.FontSize"
or "Control.FontSize"
.
Also note that many WPF controls consist of a combination of other WPF controls. If you create a style that applies to all controls of a type, you might get unexpected results. For example, if you create a style that targets the TextBlock type in a Window, the style is applied to all TextBlock
controls in the window, even if the TextBlock
is part of another control, such as a ListBox.
See also
.NET Desktop feedback