|
|||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
Preface And ThanksI am a .NET programmer, but a busy one, I do VB .NET and C#, ASP .NET / Winforms / WPF / WCF Flash Silverlight the lot. Basically I keep my toe in. But when I started writing this article series I naturally chose my favourite language (which happens to be C#). I since got an email from an individual who requested that I publish this series with source code in VB .NET and C#. I simply stated I didn't have time. So this individual (Robert Ranck) volunteered to help out, and do the translation to VB .NET, based on my orginal C# projects So for that and the subsequent VB .NET projects that you will find here I ask you to thank Robert Ranck. Cheers Robert, your contributions will surely make this series more open to all .NET developers. And another thanks also goes out Karl Shifflett (AKA the blog/article machine, also known as the Molenator) for answering my dumb VB .NET questions. And I'd also like to mention that Karl has just started a more advanced series of WPF articles (which at present will be in VB.NET, but will hopefully appear in C# as well). Karls new series will be excellent and I urge you all to encourage Karl on this series. Its not easy obligating ones self to write an entire series in one language let alone 2. Karls 1st article is located right here, and he has also published part2 now, go have a look for yourself. Personally I love them. IntroductionThis article is the 6th in my series of beginners articles for WPF. In this article we will discuss Styles/Templates. The proposed schedule for this series has been as follows:
In this article I'm aiming to cover, is a brief introduction into the following:
I will NOT be covering the usage on animations within Styles/Templates. Josh Smith has an excellent usage of animations within a Style, within this article. There is also a good MSDN article about this right here should you want to do that What Is This Article All AboutIf you are reading this and have ever tried to create an owner drawn tab/customised a button (you know override the OnPaint() and OnPaintBackGround()) then you will probably know that creating custom controls that look different to the standard controls is do-able but just not that much fun. I've done a fair ammount of WinForms custom/user controls, and I have no love for all that method overriding and mouse handling, and have often thought that there must be a better way. WPF addressed all of this, by creating 2 UI design pillars, one called STYLES and one called TEMPLATING. This article covers both of these within a WPF environment. What are StylesOverviewSimply put In this article I dont want to get to bogged down in how to create themes, I just want to cover the basics, so I'm going to show you a few things that are available within a For a
Out of these by far the most import properties are
So I think it's worth have a quick look into each of these bits on syntax. BasedOnThis is like inheritence. Where one <Style x:Key="Style1">
...
</Style>
<Style x:Key="Style2" BasedOn="{StaticResource Style1}">
...
</Style>
TargetTypeThe Target type property is used to limit which controls may use a particular style. For example if we had a Setting a valid <Style TargetType="{x:Type Button}">
....
</Style>
Setters
<Style TargetType="{x:Type Button}">
<EventSetter Event="Click" Handler="b1SetColor"/>
</Style>
However, much more typically <Style TargetType="{x:Type Button}">
<Setter Property="BackGround" Value="Yellow"/>
</Style>
Property Element SyntaxThere are also occassions where you dont want the value to be a single value, but rather a complex chunk of XAML, comprising many elements. In order to do this, XAML allows developers to use the Property Element syntax. The most likely place you will see this in <!-- Tab Item Style -->
<Style x:Key="TabItemStyle1" TargetType="{x:Type TabItem}">
<Setter Property="FocusVisualStyle" Value="{StaticResource TabItemFocusVisual}"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Padding" Value="6,1,6,1"/>
<Setter Property="BorderBrush" Value="{StaticResource TabControlNormalBorderBrush}"/>
<Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid SnapsToDevicePixels="true" Margin="0,5,0,0">
.....
.....
.....
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The important part here is the part where the <Setter Property="Template">
<Setter.Value>
.....
.....
.....
</Setter.Value>
</Setter>
TriggersThe WPF styling and templating model enables you to specify The following example shows a named <Style x:Key="Triggers" TargetType="Button">
<Style.Triggers>
<Trigger Property="IsPressed" Value="true">
<Setter Property = "Foreground" Value="Green"/>
</Trigger>
</Style.Triggers>
</Style>
There are some more types of Triggers that may be used in Styles
DataTriggersRepresents a The <Style TargetType="ListBoxItem">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=State}" Value="WA">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
There is also a special type of <Style TargetType="ListBoxItem">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=Name}" Value="Portland" />
<Condition Binding="{Binding Path=State}" Value="OR" />
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="Cyan" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
In this example the bound object must have a Name="Portland" and a State="OR", then the foreground of the corresponding ListBoxItem is set to Red. EventTriggersAre special <EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Duration="0:0:0.2"
Storyboard.TargetProperty="MaxHeight"
To="90" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Duration="0:0:1"
Storyboard.TargetProperty="MaxHeight" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
Example Styles Within The Demo AppThe attached demo app uses a fair few Here is an example of a <!-- Tab Item Style -->
<Style x:Key="TabItemStyle1" TargetType="{x:Type TabItem}">
<Setter Property="FocusVisualStyle" Value="{StaticResource TabItemFocusVisual}"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Padding" Value="6,1,6,1"/>
<Setter Property="BorderBrush" Value="{StaticResource TabControlNormalBorderBrush}"/>
<Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}"/>
<Button x:Name="btnClose" Margin="10,3,3,3"
Template="{StaticResource closeButtonTemplate}"
Background="{StaticResource buttonNormalBrush}"
IsEnabled="True"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid SnapsToDevicePixels="true" Margin="0,5,0,0">
<Border x:Name="Bd" Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="1,1,1,0" CornerRadius="10,10,0,0"
Padding="{TemplateBinding Padding}">
<ContentPresenter SnapsToDevicePixels=
"{TemplateBinding SnapsToDevicePixels}"
HorizontalAlignment="{Binding
Path=HorizontalContentAlignment,
RelativeSource={RelativeSource
AncestorType={x:Type ItemsControl}}}"
x:Name="Content" VerticalAlignment="
{Binding Path=VerticalContentAlignment,
RelativeSource={RelativeSource
AncestorType={x:Type ItemsControl}}}"
ContentSource="Header" RecognizesAccessKey="True"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" TargetName="Bd"
Value="{StaticResource TabItemHotBackground}"/>
</Trigger>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Panel.ZIndex" Value="1"/>
<Setter Property="Background" TargetName="Bd"
Value="{StaticResource TabItemSelectedBackground}"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="false"/>
<Condition Property="IsMouseOver" Value="true"/>
</MultiTrigger.Conditions>
<Setter Property="BorderBrush" TargetName="Bd"
Value="{StaticResource TabItemHotBorderBrush}"/>
</MultiTrigger>
<Trigger Property="TabStripPlacement" Value="Bottom">
<Setter Property="BorderThickness" TargetName="Bd" Value="1,0,1,1"/>
</Trigger>
<Trigger Property="TabStripPlacement" Value="Left">
<Setter Property="BorderThickness" TargetName="Bd" Value="1,1,0,1"/>
</Trigger>
<Trigger Property="TabStripPlacement" Value="Right">
<Setter Property="BorderThickness" TargetName="Bd" Value="0,1,1,1"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="TabStripPlacement" Value="Top"/>
</MultiTrigger.Conditions>
<Setter Property="Margin" Value="-2,-2,-2,-1"/>
<Setter Property="Margin" TargetName="Content" Value="0,0,0,1"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="TabStripPlacement" Value="Bottom"/>
</MultiTrigger.Conditions>
<Setter Property="Margin" Value="-2,-1,-2,-2"/>
<Setter Property="Margin" TargetName="Content" Value="0,1,0,0"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="TabStripPlacement" Value="Left"/>
</MultiTrigger.Conditions>
<Setter Property="Margin" Value="-2,-2,-1,-2"/>
<Setter Property="Margin" TargetName="Content" Value="0,0,1,0"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="TabStripPlacement" Value="Right"/>
</MultiTrigger.Conditions>
<Setter Property="Margin" Value="-1,-2,-2,-2"/>
<Setter Property="Margin" TargetName="Content" Value="1,0,0,0"/>
</MultiTrigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="Bd"
Value="{StaticResource TabItemDisabledBackground}"/>
<Setter Property="BorderBrush" TargetName="Bd"
Value="{StaticResource TabItemDisabledBorderBrush}"/>
<Setter Property="Foreground"
Value="{DynamicResource
{x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This
The demo app also contains a
In order to do this, there needed to be quite a few <!-- Brushses-->
<LinearGradientBrush x:Key="VerticalScrollBarBackground"
EndPoint="1,0" StartPoint="0,0">
<GradientStop Color="#E1E1E1" Offset="0"/>
<GradientStop Color="#EDEDED" Offset="0.20"/>
<GradientStop Color="#EDEDED" Offset="0.80"/>
<GradientStop Color="#E3E3E3" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="HorizontalScrollBarBackground"
EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#E1E1E1" Offset="0"/>
<GradientStop Color="#EDEDED" Offset="0.20"/>
<GradientStop Color="#EDEDED" Offset="0.80"/>
<GradientStop Color="#E3E3E3" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="ListBoxBackgroundBrush"
StartPoint="0,0" EndPoint="1,0.001">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="White" Offset="0.0" />
<GradientStop Color="White" Offset="0.6" />
<GradientStop Color="#DDDDDD" Offset="1.2"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="StandardBrush"
StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#CCC" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="PressedBrush"
StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#BBB" Offset="0.0"/>
<GradientStop Color="#EEE" Offset="0.1"/>
<GradientStop Color="#EEE" Offset="0.9"/>
<GradientStop Color="#FFF" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<SolidColorBrush x:Key="ScrollBarDisabledBackground" Color="#F4F4F4"/>
<SolidColorBrush x:Key="StandardBorderBrush" Color="#888" />
<SolidColorBrush x:Key="StandardBackgroundBrush" Color="#FFF" />
<SolidColorBrush x:Key="HoverBorderBrush" Color="#DDD" />
<SolidColorBrush x:Key="SelectedBackgroundBrush" Color="Gray" />
<SolidColorBrush x:Key="SelectedForegroundBrush" Color="White" />
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />
<SolidColorBrush x:Key="NormalBrush" Color="#888" />
<SolidColorBrush x:Key="NormalBorderBrush" Color="#888" />
<SolidColorBrush x:Key="HorizontalNormalBrush" Color="#888" />
<SolidColorBrush x:Key="HorizontalNormalBorderBrush" Color="#888" />
<SolidColorBrush x:Key="GlyphBrush" Color="#444" />
<!-- ScrollBarButton Vertical -->
<Style x:Key="VerticalScrollBarPageButton" TargetType="{x:Type RepeatButton}">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Focusable" Value="false"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
...
...
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ScrollBarButton Horizontal -->
<Style x:Key="HorizontalScrollBarPageButton" TargetType="{x:Type RepeatButton}">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Focusable" Value="false"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
...
...
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Scroll Buttons Down-->
<Style x:Key="RepeatButtonStyleDown" TargetType="{x:Type RepeatButton}">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Focusable" Value="false"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
...
...
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Scroll Buttons Up-->
<Style x:Key="RepeatButtonStyleUp" TargetType="{x:Type RepeatButton}">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Focusable" Value="false"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
...
...
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Scroll Thumb Style-->
<Style x:Key="ThumbStyle1" TargetType="{x:Type Thumb}">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
...
...
</ | ||||||||||||||||||||||||||||||||||||||||||||