Silverlight Bind VisualState to different Targets - silverlight

I'm using the following border style:
<!-- Border Style -->
<Style TargetType="Border">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5, 1" StartPoint="0.5 ,0" MappingMode="RelativeToBoundingBox">
<GradientStop Color="#00000000" Offset="0" />
<GradientStop Color="#FFFFFEBB" Offset="0.116"/>
<GradientStop Color="#FFFFFEBB" Offset="0.897"/>
<GradientStop Color="#00000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="Opacity" Value="0"/>
<Setter Property="OpacityMask">
<Setter.Value>
<LinearGradientBrush EndPoint="1.0 ,0.5" StartPoint="0.0 ,0.5" MappingMode="RelativeToBoundingBox">
<GradientStop/>
<GradientStop Color="#FF000000" Offset="0.1"/>
<GradientStop Color="#FF000000" Offset="0.9"/>
<GradientStop Color="#00000000" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="RenderTransform">
<Setter.Value>
<CompositeTransform ScaleX="1.03" ScaleY="1.01"/>
</Setter.Value>
</Setter>
</Style>
There are three Borders in my application. I want to animate the opacity of the border when the mouse cursor is entering the border. In order to do that, I'm using a VisualState:
<VisualState x:Name="MouseOverState">
<Storyboard>
<DoubleAnimation To="1" Storyboard.TargetProperty="(UIElement.Opacity)" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
Do I need to define three different VisualStates and set the Storyboard.TargetName property? Or is there a way to use the same VisualState for many objects?
PS:
I know that there is a TargetName and TargetObject Property in the GoToStateAction, but I can't get it to work:
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<ei:GoToStateAction StateName="MouseOverState" TargetName="border0"/>
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<ei:GoToStateAction StateName="DefaultState" TargetName="border0"/>
</i:EventTrigger>
</i:Interaction.Triggers>

I'd be inclined to create a custom control deriving from the ContentControl.
In themes\generic.xaml
<Style TargetType="local:MyBorder">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5, 1" StartPoint="0.5 ,0" MappingMode="RelativeToBoundingBox">
<GradientStop Color="#00000000" Offset="0" />
<GradientStop Color="#FFFFFEBB" Offset="0.116"/>
<GradientStop Color="#FFFFFEBB" Offset="0.897"/>
<GradientStop Color="#00000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="OpacityMask">
<Setter.Value>
<LinearGradientBrush EndPoint="1.0 ,0.5" StartPoint="0.0 ,0.5" MappingMode="RelativeToBoundingBox">
<GradientStop/>
<GradientStop Color="#FF000000" Offset="0.1"/>
<GradientStop Color="#FF000000" Offset="0.9"/>
<GradientStop Color="#00000000" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="RenderTransform">
<Setter.Value>
<CompositeTransform ScaleX="1.03" ScaleY="1.01"/>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="#FF000000"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MyBorder">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Opacity="0"
>
<vsm:VisualStateManager.VisualStateGroups>
<vsm:VisualStateGroup x:Name="CommonStates">
<vsm:VisualState x:Name="Normal"/>
<vsm:VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimation To="1" Storyboard.TargetProperty="(UIElement.Opacity)" />
</Storyboard>
</vsm:VisualState>
</vsm:VisualStateGroup >
</vsm:VisualStateManager>
<ContentPresenter
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Cursor="{TemplateBinding Cursor}"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You just need to add the MouseEnter MouseLeave set the visual state of the control accordingly.
Now you can simply drop local:MyBorder where you need one of these borders.

Related

Set Fill to LinearGradientBrush on Button Click

For reference, I am using this MSDN tutorial: https://msdn.microsoft.com/en-us/library/bb613545(v=vs.100).aspx
I have finished the tutorial, and I simply wanted to change the Click EventTrigger animation from the 360 spin to a simple change of the LinearGradientBrush.
My GradientStopCollections as per the tutorial. One is an altered one that I want to use in the animation when I click the button
<GradientStopCollection x:Key="MyGlassGradientStopsResource">
<GradientStop Offset="0.2" Color="WhiteSmoke" />
<GradientStop Offset="0.4" Color="Transparent" />
<GradientStop Offset="0.5" Color="WhiteSmoke" />
<GradientStop Offset="0.75" Color="Transparent" />
<GradientStop Offset="0.9" Color="WhiteSmoke" />
<GradientStop Offset="1" Color="Transparent" />
</GradientStopCollection>
<GradientStopCollection x:Key="MyRedGlassGradientStopsResource">
<GradientStop Offset="0.2" Color="IndianRed" />
<GradientStop Offset="0.4" Color="Transparent" />
<GradientStop Offset="0.5" Color="IndianRed" />
<GradientStop Offset="0.75" Color="Transparent" />
<GradientStop Offset="0.9" Color="IndianRed" />
<GradientStop Offset="1" Color="Transparent" />
</GradientStopCollection>
<LinearGradientBrush x:Key="MyGlassBrushResource"
GradientStops="{StaticResource MyGlassGradientStopsResource}"
Opacity="0.75"
StartPoint="0,0"
EndPoint="1,1" />
<LinearGradientBrush x:Key="MyRedGlassBrushResource"
GradientStops="{StaticResource MyRedGlassGradientStopsResource}"
Opacity="0.75"
StartPoint="0,0"
EndPoint="1,1" />
The button itself. The rectangle being affected is the glassCube rectangle.
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="{StaticResource GrayBlueGradientBrush}" />
<Setter Property="Width" Value="90" />
<Setter Property="Margin" Value="10" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
ClipToBounds="True">
<!-- Outer rectangle with rounded corners -->
<Rectangle x:Name="outerRectangle"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Fill="Transparent"
RadiusX="20"
RadiusY="20"
Stroke="{TemplateBinding Background}"
StrokeThickness="5" />
<!-- Inner rectangle with rouded corners -->
<Rectangle x:Name="innerRectangle"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Fill="{TemplateBinding Background}"
RadiusX="20"
RadiusY="20"
Stroke="Transparent"
StrokeThickness="20" />
<!-- Glass Rectangle -->
<Rectangle x:Name="glassCube"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Fill="{StaticResource MyGlassBrushResource}"
Opacity="0"
RadiusX="10"
RadiusY="10"
RenderTransformOrigin="0.5,0.5"
StrokeThickness="2">
<Rectangle.Stroke>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.0" Color="LightBlue" />
<GradientStop Offset="1.0" Color="Gray" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Rectangle.Stroke>
<!--
These tranforms have no effect as they are declared here.
The reason the transforms are included is to be targets for animation
(See later)
-->
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform />
<RotateTransform />
</TransformGroup>
</Rectangle.RenderTransform>
<!-- A BevelBitmapEffect if applied to give the button a "Bevelled" look -->
<Rectangle.BitmapEffect>
<BevelBitmapEffect />
</Rectangle.BitmapEffect>
</Rectangle>
<!-- Present content (text) of the button -->
<DockPanel Name="myContentPresenterDockPanel">
<ContentPresenter x:Name="myContentPresenter"
Margin="20"
Content="{TemplateBinding Content}"
TextBlock.Foreground="Black" />
</DockPanel>
</Grid>
</ControlTemplate>
<!---Snipped the triggers-->
</Setter.Value>
And this is the trigger I am trying to use to change the Fill of the glassCube rectangle from the MyGlassGradientStopsResource brush to the MyGlassGradientStopsResource brush.
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.5"
Storyboard.TargetName="glassCube"
Storyboard.TargetProperty="Rectangle.Fill"
To="{StaticResource MyRedGlassBrushResource}"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
However, trying to do this gives me an XAMLParseException. The error in the error list shows as An object of the type "System.Windows.Media.LinearGradientBrush" cannot be applied to a property that expects the type "System.Nullable`1[[System.Windows.Media.Color, PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]".
Any idea what I might be doing wrong? I've tried finding out how to change a Fill to a different LinearGradientBrush in an EventTrigger, but to no avail. I may just suck at wording my searches, or at searching in general. Any help is greatly appreciated
I did some modification of your style. Also, i fixed your Storyboard.
It should now work properly.
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="{StaticResource GrayBlueGradientBrush}" />
<Setter Property="Width" Value="90" />
<Setter Property="Margin" Value="10" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" ClipToBounds="True">
<Rectangle x:Name="outerRectangle" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="Transparent" RadiusX="20" RadiusY="20" Stroke="{TemplateBinding Background}" StrokeThickness="5" />
<Rectangle x:Name="innerRectangle" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="{TemplateBinding Background}" RadiusX="20" RadiusY="20" Stroke="Transparent" StrokeThickness="20" />
<Rectangle x:Name="glassCube" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Opacity="1" RadiusX="10" RadiusY="10" RenderTransformOrigin="0.5,0.5" StrokeThickness="2">
<Rectangle.Style>
<Style TargetType="Rectangle">
<Setter Property="Fill" Value="{StaticResource MyGlassBrushResource}"></Setter>
</Style>
</Rectangle.Style>
<Rectangle.Stroke>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.0" Color="LightBlue" />
<GradientStop Offset="1.0" Color="Gray" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Rectangle.Stroke>
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform />
<RotateTransform />
</TransformGroup>
</Rectangle.RenderTransform>
<!-- A BevelBitmapEffect if applied to give the button a "Bevelled" look -->
<Rectangle.BitmapEffect>
<BevelBitmapEffect />
</Rectangle.BitmapEffect>
</Rectangle>
<!-- Present content (text) of the button -->
<DockPanel Name="myContentPresenterDockPanel" HorizontalAlignment="Center">
<ContentPresenter x:Name="myContentPresenter" Content="{TemplateBinding Content}" TextBlock.Foreground="Black" />
</DockPanel>
</Grid>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="glassCube" Storyboard.TargetProperty="Fill" Duration="0:0:0.5" BeginTime="0">
<ObjectAnimationUsingKeyFrames.KeyFrames>
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{StaticResource MyRedGlassBrushResource}" />
</ObjectAnimationUsingKeyFrames.KeyFrames>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Note
You cannot set a Brush as ColorAnimation. Use a ObjectAnimationUsingKeyFrames instead. If you still need a BrushAnimation, have a look here

Change border color of Button on PointerOver

I have a Button with ControlTemplate:
<Page.Resources>
<ControlTemplate x:Key="ButtonTemplate" TargetType="Button">
<Border BorderBrush="Orange" BorderThickness="3" CornerRadius="2">
<Border.Background>
<LinearGradientBrush>
<GradientStopCollection>
<GradientStop Offset="0" Color="LimeGreen"></GradientStop>
<GradientStop Offset="1" Color="LightBlue"></GradientStop>
</GradientStopCollection>
</LinearGradientBrush>
</Border.Background>
<ContentPresenter Content="{TemplateBinding Content}" />
</Border>
</ControlTemplate>
</Page.Resources>
<Button Margin="10" Width="110" Padding="5" Height="30"
Template="{StaticResource ButtonTemplate}">Test</Button>
Now I want to change of border color when mouse pointer over the button.
Here is my version:
<Page.Resources>
<ControlTemplate x:Key="ButtonTemplate" TargetType="Button">
<Border x:Name="Border" BorderBrush="Orange" BorderThickness="3" CornerRadius="2">
<Border.Background>
<LinearGradientBrush>
<GradientStopCollection>
<GradientStop Offset="0" Color="LimeGreen"></GradientStop>
<GradientStop Offset="1" Color="LightBlue"></GradientStop>
</GradientStopCollection>
</LinearGradientBrush>
</Border.Background>
<ContentPresenter Content="{TemplateBinding Content}" />
</Border>
<VisualStateManager>
<VisualStateGroup>
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName="Border"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="Blue" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager>
</ControlTemplate>
</Page.Resources>
But it returns too many errors. For example, "Property VisualTree can be defined only one time". How can I fix it?
You get the error because ControlTemplate has 2 root elements Border and VisualStateManager. Instead of VisualStateManager you need to set VisualStateManager.VisualStateGroupsand it needs to be set against root element of the ControlTemplate so either move it into Border or create, for example, Grid around both Border and VisualStateManager.VisualStateGroups
<ControlTemplate x:Key="ButtonTemplate" TargetType="Button">
<Grid>
<Border x:Name="Border" BorderBrush="Orange" BorderThickness="3" CornerRadius="2">
<Border.Background>
<LinearGradientBrush>
<GradientStopCollection>
<GradientStop Offset="0" Color="LimeGreen"/>
<GradientStop Offset="1" Color="LightBlue"/>
</GradientStopCollection>
</LinearGradientBrush>
</Border.Background>
<ContentPresenter Content="{TemplateBinding Content}" />
</Border>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName="Border"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="Blue" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>

Slow ComboBox Performance

As explained in the following article http://vbcity.com/blogs/xtab/archive/2009/12/15/wpf-using-a-virtualizingstackpanel-to-improve-combobox-performance.aspx, I use the VirtualizingStackPanel to improve the performance of my project's ComboBoxes.
And it works great ... until I apply a style to ComboBox to change the layout (I found the style here : http://msdn.microsoft.com/en-us/library/ee230084.aspx)
Here is the source code of a sample which demonstrate the matter (figuring that ItemSource propery of the ComboBox are filled with 10 000 items).
If anyone has an idea ...
<Window.Resources>
<!-- Fill Brushes -->
<LinearGradientBrush x:Key="NormalBrush" 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="HorizontalNormalBrush" StartPoint="0,0" EndPoint="1,0">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#CCC" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="LightBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#EEE" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="HorizontalLightBrush" StartPoint="0,0" EndPoint="1,0">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#EEE" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="DarkBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#FFF" Offset="0.0"/>
<GradientStop Color="#AAA" 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="DisabledForegroundBrush" Color="Black" />
<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#E5E5E5" />
<SolidColorBrush x:Key="WindowBackgroundBrush" Color="#FFF" />
<SolidColorBrush x:Key="SelectedBackgroundBrush" Color="#DDD" />
<!-- Border Brushes -->
<LinearGradientBrush x:Key="NormalBorderBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#AAA" Offset="0.0"/>
<GradientStop Color="#AAA" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="HorizontalNormalBorderBrush" StartPoint="0,0" EndPoint="1,0">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#AAA" Offset="0.0"/>
<GradientStop Color="#AAA" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="DefaultedBorderBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#AAA" Offset="0.0"/>
<GradientStop Color="#AAA" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="PressedBorderBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#AAA" Offset="0.0"/>
<GradientStop Color="#AAA" Offset="1.0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<SolidColorBrush x:Key="DisabledBorderBrush" Color="#AAA" />
<SolidColorBrush x:Key="SolidBorderBrush" Color="#888" />
<SolidColorBrush x:Key="LightBorderBrush" Color="#AAA" />
<!-- Miscellaneous Brushes -->
<SolidColorBrush x:Key="GlyphBrush" Color="#444" />
<SolidColorBrush x:Key="LightColorBrush" Color="#DDD" />
<ControlTemplate x:Key="ComboBoxToggleButton" TargetType="ToggleButton">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="16" />
</Grid.ColumnDefinitions>
<Border x:Name="Border" Grid.ColumnSpan="2" CornerRadius="2" Background="{StaticResource NormalBrush}" BorderBrush="{StaticResource NormalBorderBrush}" BorderThickness="1" />
<Border x:Name="Border2" Grid.Column="0" CornerRadius="2,0,0,2" Margin="1" Background="{StaticResource WindowBackgroundBrush}" BorderBrush="{StaticResource NormalBorderBrush}" BorderThickness="0,0,1,0" />
<Path x:Name="Arrow" Grid.Column="1" Fill="{StaticResource GlyphBrush}" HorizontalAlignment="Center" VerticalAlignment="Center" Data="M 0 0 L 4 4 L 8 0 Z"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ToggleButton.IsMouseOver" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource DarkBrush}" />
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource PressedBrush}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Border" Property="Background" Value="{StaticResource DisabledBackgroundBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource DisabledBorderBrush}" />
<Setter TargetName="Border2" Property="Background" Value="{StaticResource DisabledBackgroundBrush}" />
<Setter TargetName="Border2" Property="BorderBrush" Value="{StaticResource DisabledBorderBrush}" />
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
<Setter TargetName="Arrow" Property="Fill" Value="{StaticResource DisabledForegroundBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="ComboBoxTextBox" TargetType="TextBox">
<Border x:Name="PART_ContentHost" Focusable="False" Background="{TemplateBinding Background}" />
</ControlTemplate>
<Style x:Key="ComboBoxBaseStyle" TargetType="ComboBox">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="MinHeight" Value="20"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<ToggleButton Name="ToggleButton" Template="{StaticResource ComboBoxToggleButton}" Grid.Column="2" Focusable="false" IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press">
</ToggleButton>
<ContentPresenter Name="ContentSite" IsHitTestVisible="False" Content="{TemplateBinding SelectionBoxItem}" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" Margin="3,3,23,3" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBox x:Name="PART_EditableTextBox" Style="{x:Null}" Template="{StaticResource ComboBoxTextBox}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="3,3,23,3" Focusable="True" Background="Transparent" Visibility="Hidden" IsReadOnly="{TemplateBinding IsReadOnly}"/>
<Popup Name="Popup" Placement="Bottom" IsOpen="{TemplateBinding IsDropDownOpen}" AllowsTransparency="True" Focusable="False" PopupAnimation="Slide">
<Grid Name="DropDown" SnapsToDevicePixels="True" MinWidth="{TemplateBinding ActualWidth}" MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border x:Name="DropDownBorder" Background="{StaticResource WindowBackgroundBrush}" BorderThickness="1" BorderBrush="{StaticResource SolidBorderBrush}"/>
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="false">
<Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
<Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="true">
<Setter TargetName="DropDownBorder" Property="CornerRadius" Value="4"/>
<Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0,0"/>
</Trigger>
<Trigger Property="IsEditable" Value="true">
<Setter Property="IsTabStop" Value="false"/>
<Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible"/>
<Setter TargetName="ContentSite" Property="Visibility" Value="Hidden"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<ComboBox x:Name="CustomerComboBox_WithoutStyle" SelectedValuePath="Id" DisplayMemberPath="Text" >
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
<ComboBox x:Name="CustomerComboBox_WithStyle" SelectedValuePath="Id" DisplayMemberPath="Text" Style="{StaticResource ComboBoxBaseStyle}" >
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
</StackPanel>
The problem of your style is that it does not use any kind of UI Virtualization.
Try replacing the StackPanel with a VirtualizingStackpanel and set the VirtualizationMode to Recycle and you will see a huge performance boost.
Your approach forces WPF to realize a container and FrameworkElement for each of your 10k items, which takes an eternity as you have only 1 UI thread.
Just replace
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
with
<VirtualizingStackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
and see if it gets faster.
To be more precise, you override the ItemsPanel in your derived styles, but have no "ItemsPresenter" in the base style. Instead to use the StackPanel "hardcoded"
So many items probably is the result of a (UI) design flaw.
Try using a listbox or multiple combo boxes where the first combo box is a category and second is a sub category of the first.
having 10000 items in a combox is not very good design. MaxDropDownItems might be able to help you as less rendering is required. (this is the number of visible items shown when clicking the dropdown)
But, you should consider using a listbox. When you apply a listbox you should uses pages and on each page have 1000 records. Or use a search box

WPF progressbar style is blocky?

I'm using an indeterminate progressbar in my application and I get this bad animation of a series of blocks running horizontally. Isn't there a better style available like vista or windows 7?
Your progress bar has a style that corresponds to your current windows theme. If you run your application on Windows 7 with an Aero theme your progress bar will look accordingly.
If you want it to look always the same (no matter what windows theme is selected) you will need to define your own style for the progress bar.
Here is the style from the Aero Normal Color theme:
<LinearGradientBrush x:Key="ProgressBarBorderBrush"
EndPoint="0,1"
StartPoint="0,0">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#B2B2B2"
Offset="0"/>
<GradientStop Color="#8C8C8C"
Offset="1"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="ProgressBarBackground"
EndPoint="1,0"
StartPoint="0,0">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#BABABA"
Offset="0"/>
<GradientStop Color="#C7C7C7"
Offset="0.5"/>
<GradientStop Color="#BABABA"
Offset="1"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="ProgressBarTopHighlight"
StartPoint="0,0"
EndPoint="0,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#80FFFFFF"
Offset="0.05"/>
<GradientStop Color="#00FFFFFF"
Offset="0.25"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="ProgressBarGlassyHighlight"
StartPoint="0,0"
EndPoint="0,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#50FFFFFF"
Offset="0.5385"/>
<GradientStop Color="#00FFFFFF"
Offset="0.5385"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="ProgressBarIndicatorGlassyHighlight"
StartPoint="0,0"
EndPoint="0,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#90FFFFFF"
Offset="0.5385"/>
<GradientStop Color="#00FFFFFF"
Offset="0.5385"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<RadialGradientBrush x:Key="ProgressBarIndicatorLightingEffectLeft"
RadiusX="1"
RadiusY="1"
RelativeTransform="1,0,0,1,0.5,0.5">
<RadialGradientBrush.GradientStops>
<GradientStop Color="#60FFFFC4"
Offset="0"/>
<GradientStop Color="#00FFFFC4"
Offset="1"/>
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>
<LinearGradientBrush x:Key="ProgressBarIndicatorLightingEffect"
StartPoint="0,1"
EndPoint="0,0">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#60FFFFC4"
Offset="0"/>
<GradientStop Color="#00FFFFC4"
Offset="1"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<RadialGradientBrush x:Key="ProgressBarIndicatorLightingEffectRight"
RadiusX="1"
RadiusY="1"
RelativeTransform="1,0,0,1,-0.5,0.5">
<RadialGradientBrush.GradientStops>
<GradientStop Color="#60FFFFC4"
Offset="0"/>
<GradientStop Color="#00FFFFC4"
Offset="1"/>
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>
<LinearGradientBrush x:Key="ProgressBarIndicatorDarkEdgeLeft"
StartPoint="0,0"
EndPoint="1,0">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#0C000000"
Offset="0"/>
<GradientStop Color="#20000000"
Offset="0.3"/>
<GradientStop Color="#00000000"
Offset="1"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="ProgressBarIndicatorDarkEdgeRight"
StartPoint="0,0"
EndPoint="1,0">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#00000000"
Offset="0"/>
<GradientStop Color="#20000000"
Offset="0.7"/>
<GradientStop Color="#0C000000"
Offset="1"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="ProgressBarIndicatorAnimatedFill"
StartPoint="0,0"
EndPoint="1,0">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#00FFFFFF"
Offset="0"/>
<GradientStop Color="#60FFFFFF"
Offset="0.4"/>
<GradientStop Color="#60FFFFFF"
Offset="0.6"/>
<GradientStop Color="#00FFFFFF"
Offset="1"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<Style x:Key="{x:Type ProgressBar}"
TargetType="{x:Type ProgressBar}">
<Setter Property="Foreground"
Value="#01D328"/>
<Setter Property="Background"
Value="{StaticResource ProgressBarBackground}"/>
<Setter Property="BorderBrush"
Value="{StaticResource ProgressBarBorderBrush}"/>
<Setter Property="BorderThickness"
Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ProgressBar}">
<Grid Name="TemplateRoot"
SnapsToDevicePixels="true">
<Rectangle Fill="{TemplateBinding Background}"
RadiusX="2"
RadiusY="2"/>
<Border Background="{StaticResource ProgressBarGlassyHighlight}"
Margin="1"
CornerRadius="2"/>
<Border BorderBrush="#80FFFFFF"
Background="{StaticResource ProgressBarTopHighlight}"
BorderThickness="1,0,1,1"
Margin="1"/>
<Rectangle Name="PART_Track"
Margin="1"/>
<Decorator x:Name="PART_Indicator"
HorizontalAlignment="Left"
Margin="1">
<Grid Name="Foreground">
<Rectangle x:Name="Indicator"
Fill="{TemplateBinding Foreground}"/>
<Grid x:Name="Animation" ClipToBounds="true">
<Rectangle x:Name="PART_GlowRect" Width="100"
Fill="{StaticResource ProgressBarIndicatorAnimatedFill}"
Margin="-100,0,0,0"
HorizontalAlignment="Left">
</Rectangle>
</Grid>
<Grid x:Name="Overlay">
<Grid.ColumnDefinitions>
<ColumnDefinition MaxWidth="15"/>
<ColumnDefinition Width="0.1*"/>
<ColumnDefinition MaxWidth="15"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Rectangle x:Name="LeftDark"
Grid.RowSpan="2"
Fill="{StaticResource ProgressBarIndicatorDarkEdgeLeft}"
RadiusX="1"
RadiusY="1"
Margin="1,1,0,1"/>
<Rectangle x:Name="RightDark"
Grid.RowSpan="2"
Grid.Column="2"
RadiusX="1"
RadiusY="1"
Fill="{StaticResource ProgressBarIndicatorDarkEdgeRight}"
Margin="0,1,1,1"/>
<Rectangle x:Name="LeftLight"
Grid.Column="0"
Grid.Row="2"
Fill="{StaticResource ProgressBarIndicatorLightingEffectLeft}"/>
<Rectangle x:Name="CenterLight"
Grid.Column="1"
Grid.Row="2"
Fill="{StaticResource ProgressBarIndicatorLightingEffect}"/>
<Rectangle x:Name="RightLight"
Grid.Column="2"
Grid.Row="2"
Fill="{StaticResource ProgressBarIndicatorLightingEffectRight}"/>
<Border x:Name="Highlight1"
Grid.RowSpan="2"
Grid.ColumnSpan="3"
Background="{StaticResource ProgressBarIndicatorGlassyHighlight}"/>
<Border x:Name="Highlight2"
Grid.RowSpan="2"
Grid.ColumnSpan="3"
Background="{StaticResource ProgressBarTopHighlight}"/>
</Grid>
</Grid>
</Decorator>
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
CornerRadius="2"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="Orientation"
Value="Vertical">
<Setter TargetName="TemplateRoot"
Property="LayoutTransform">
<Setter.Value>
<RotateTransform Angle="-90"/>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsIndeterminate"
Value="true">
<Setter TargetName="LeftDark"
Property="Visibility"
Value="Collapsed"/>
<Setter TargetName="RightDark"
Property="Visibility"
Value="Collapsed"/>
<Setter TargetName="LeftLight"
Property="Visibility"
Value="Collapsed"/>
<Setter TargetName="CenterLight"
Property="Visibility"
Value="Collapsed"/>
<Setter TargetName="RightLight"
Property="Visibility"
Value="Collapsed"/>
<Setter TargetName="Indicator"
Property="Visibility"
Value="Collapsed"/>
</Trigger>
<Trigger Property="IsIndeterminate"
Value="false">
<Setter TargetName="Animation"
Property="Background"
Value="#80B5FFA9"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Put this code in the Themes/Generic.xaml file in your application and your progress bars will always have this style.
This is another one... very simple flat progress bar for IsInderminate mode-
<ControlTemplate x:Key="CustomProgressBar" TargetType="ProgressBar" >
<Grid Name="TemplateRoot" SnapsToDevicePixels="True">
<Rectangle RadiusX="2" RadiusY="2" Fill="Transparent" />
<Border CornerRadius="0,0,0,0" Margin="1,1,1,1">
<Border.Background>
<SolidColorBrush Color="Transparent"/>
</Border.Background>
</Border>
<Border BorderThickness="0,0,0,0" BorderBrush="Transparent" Margin="1,1,1,1">
<Border.Background>
<SolidColorBrush Color="Transparent"/>
</Border.Background>
</Border>
<Rectangle Name="PART_Track" Margin="1,1,1,1" />
<Decorator Name="PART_Indicator" Margin="1,1,1,1" HorizontalAlignment="Left">
<Grid Name="Foreground">
<Rectangle Fill="Transparent" Name="Indicator" />
<Grid Name="Animation" ClipToBounds="True">
<Border Name="PART_GlowRect" Width="100" Margin="0,0,0,0" HorizontalAlignment="Left" Background="LightBlue"/>
</Grid>
<Grid Name="Overlay">
</Grid>
</Grid>
</Decorator>
<Border BorderThickness="0" CornerRadius="0,0,0,0" BorderBrush="Transparent" />
</Grid>
</ControlTemplate>
This is a custom progress bar I made from Suneet's example, but with IsIndeterminate animation working in .NET 3.5 :
<Style x:Key="{x:Type ProgressBar}" TargetType="{x:Type ProgressBar}">
<Setter Property="Foreground" Value="#54bdcd"/>
<Setter Property="Background" Value="#000000"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ProgressBar}">
<Grid Name="TemplateRoot" SnapsToDevicePixels="true">
<Rectangle Fill="{TemplateBinding Background}"/>
<Rectangle Name="PART_Track" Margin="0"/>
<Decorator x:Name="PART_Indicator" HorizontalAlignment="Left" Margin="0">
<Grid Name="Foreground">
<Rectangle Fill="{TemplateBinding Foreground}" Name="Indicator" />
<Grid Name="Animation" ClipToBounds="True">
<Border Name="PART_GlowRect" Margin="0,0,0,0" HorizontalAlignment="Left" Background="{TemplateBinding Foreground}"/>
</Grid>
<Grid Name="Overlay">
</Grid>
</Grid>
</Decorator>
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsIndeterminate" Value="true">
<Setter TargetName="Indicator" Property="Fill" Value="Transparent" />
<Setter TargetName="PART_GlowRect" Property="Width" Value="100" />
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation
Storyboard.TargetName="PART_GlowRect"
Storyboard.TargetProperty="Margin"
From="-50,0,0,0" To="400,0,0,0" Duration="0:0:2"
AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This is kinda a hack because I move the indeterminate bar back and forth by changing its marginleft value, but in my case it was affordable because my progress bar was a fixed width.
If you have a better idea, feel free to change the storyboard part.
This page helped me a lot.
Here is another one that supports normal and intermediate mode:
<Style TargetType="{x:Type ProgressBar}">
<Setter Property="Foreground" Value="#1BA1E2"/>
<Setter Property="Background" Value="#EEEEEE"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ProgressBar}">
<Grid Name="TemplateRoot" SnapsToDevicePixels="true">
<Rectangle Fill="{TemplateBinding Background}"/>
<Rectangle Name="PART_Track" Margin="0"/>
<Decorator x:Name="PART_Indicator" HorizontalAlignment="Left" Margin="0">
<Grid Name="Foreground">
<Rectangle Fill="{TemplateBinding Foreground}" Name="Indicator" />
<Grid x:Name="Animation" ClipToBounds="true" Visibility="Hidden">
<Rectangle Fill="{TemplateBinding Background}" Name="HiderPre" Margin="0,0,50,0">
<Rectangle.RenderTransform>
<ScaleTransform x:Name="HiderPreTransform" ScaleX="0"/>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Fill="{TemplateBinding Background}" Name="HiderPost" RenderTransformOrigin="1, 0" Margin="50,0,0,0">
<Rectangle.RenderTransform>
<ScaleTransform x:Name="HiderPostTransform" ScaleX="1" />
</Rectangle.RenderTransform>
</Rectangle>
</Grid>
<Grid Name="Overlay">
</Grid>
</Grid>
</Decorator>
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsIndeterminate" Value="true">
<Setter TargetName="Animation" Property="Visibility" Value="Visible" />
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever">
<DoubleAnimation
Storyboard.TargetName="HiderPreTransform"
Storyboard.TargetProperty="(ScaleTransform.ScaleX)"
To="1"
Duration="0:00:4" AutoReverse="True"/>
<DoubleAnimation
Storyboard.TargetName="HiderPostTransform"
Storyboard.TargetProperty="(ScaleTransform.ScaleX)"
To="0"
Duration="0:00:4" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Gray" />
</Trigger>
</Style.Triggers>
</Style>
The simplest approach I could find is based heavily on https://stackoverflow.com/a/19737148/3195477 but even more simplified.
This produces a simple flat look:
<ProgressBar>
<ProgressBar.Template>
<ControlTemplate TargetType="ProgressBar">
<Border
BorderBrush="Black"
BorderThickness="1"
Background="LightGray"
>
<Grid x:Name="PART_Track">
<Rectangle
x:Name="PART_Indicator"
HorizontalAlignment="Left"
Fill="Blue"
/>
</Grid>
</Border>
</ControlTemplate>
</ProgressBar.Template>
</ProgressBar>
The "trick" is to just minimally replace the named parts with very simple alternatives. You don't necessarily need complex gradients etc. to improve on the default appearance, although that's a matter of opinion.

Slider On/Off Switch in WPF

I am looking for a WPF tutorial on creating a slide ON/OFF switch like on the iPhone.
Here is an example (the "Send all traffic" option) https://secure-tunnel.com/support/software_setup/iphone/images/iphone_vpn_settings.jpg
I haven't seen a tutorial on this exact problem, but i guess you can start by launching Expression Blend and putting a CheckBox on it. Then select the CheckBox, go to main menu - Object -> Edit Style -> Edit a Copy
This will make Blend generate the default style of CheckBox so you're able to modify it. Look at how things work there and you'll be able to achieve some results.
Basically (besides colors and brushes stuff) you'll need to look at triggers hooked up to the IsChecked property.
E.g. when IsChecked is True you move the rectangle to one of the sides, show the ON word and hide the OFF word. To animate this you only need to add trigger in- and out- animations.
UPD:
I've spent 10-15 minutes in blend to make a "prototype":
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="CheckBoxIPhone.Window1"
x:Name="Window"
Title="Window1"
Width="320"
Height="240"
FontFamily="Segoe UI"
FontSize="20"
WindowStartupLocation="CenterScreen"
>
<Window.Resources>
<Style x:Key="CheckBoxStyle1" TargetType="{x:Type CheckBox}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"/>
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<ControlTemplate.Resources>
<Storyboard x:Key="OnChecking">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="slider" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="25"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="OnUnchecking">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="slider" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<ThicknessAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="slider" Storyboard.TargetProperty="(FrameworkElement.Margin)">
<SplineThicknessKeyFrame KeyTime="00:00:00.3000000" Value="1,1,1,1"/>
</ThicknessAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
<DockPanel x:Name="dockPanel">
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" ContentTemplate="{TemplateBinding ContentTemplate}" RecognizesAccessKey="True" VerticalAlignment="Center"/>
<Grid Margin="5,5,0,5" Width="50" Background="#FFC0CCD9">
<TextBlock Text="ON" TextWrapping="Wrap" FontWeight="Bold" FontSize="12" HorizontalAlignment="Right" Margin="0,0,3,0"/>
<TextBlock HorizontalAlignment="Left" Margin="2,0,0,0" FontSize="12" FontWeight="Bold" Text="OFF" TextWrapping="Wrap"/>
<Border HorizontalAlignment="Left" x:Name="slider" Width="23" BorderThickness="1,1,1,1" CornerRadius="3,3,3,3" RenderTransformOrigin="0.5,0.5" Margin="1,1,1,1">
<Border.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1" ScaleY="1"/>
<SkewTransform AngleX="0" AngleY="0"/>
<RotateTransform Angle="0"/>
<TranslateTransform X="0" Y="0"/>
</TransformGroup>
</Border.RenderTransform>
<Border.BorderBrush>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFFFFFFF" Offset="0"/>
<GradientStop Color="#FF4490FF" Offset="1"/>
</LinearGradientBrush>
</Border.BorderBrush>
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF8AB4FF" Offset="1"/>
<GradientStop Color="#FFD1E2FF" Offset="0"/>
</LinearGradientBrush>
</Border.Background>
</Border>
</Grid>
</DockPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource OnUnchecking}" x:Name="OnUnchecking_BeginStoryboard"/>
</Trigger.ExitActions>
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource OnChecking}" x:Name="OnChecking_BeginStoryboard"/>
</Trigger.EnterActions>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid x:Name="LayoutRoot">
<CheckBox HorizontalAlignment="Center" Style="{DynamicResource CheckBoxStyle1}" VerticalAlignment="Center" Content="CheckBox"/>
</Grid>
</Window>
I'm also suggesting you to read about Styles and Templates in WPF if you're interested.
I created some styles based on the post by arconaut in orange and blue.
Screenshot:
I wanted my style to closer match the On/Off Switch style of iOS devices. One difference in this style is, that the sliding animation does only slide the switch and not the indicators below. Maybe if i can find some time I will modify it that way. Until then I want to share my result. It's not perfect, but here is the code.
<LinearGradientBrush x:Key="CheckedBlue" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#FF285AB3" Offset="0" />
<GradientStop Color="#FF4184EC" Offset="0.5" />
<GradientStop Color="#FF558BED" Offset="0.5" />
<GradientStop Color="#FF7DACF0" Offset="1" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="CheckedOrange" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#FFCA6A13" Offset="0" />
<GradientStop Color="#FFF67D0C" Offset="0.2" />
<GradientStop Color="#FFFE7F0C" Offset="0.2" />
<GradientStop Color="#FFFA8E12" Offset="0.5" />
<GradientStop Color="#FFFF981D" Offset="0.5" />
<GradientStop Color="#FFFCBC5A" Offset="1" />
</LinearGradientBrush>
<SolidColorBrush x:Key="CheckedOrangeBorder" Color="#FF8E4A1B" />
<SolidColorBrush x:Key="CheckedBlueBorder" Color="#FF143874" />
<Style x:Key="OrangeSwitchStyle" TargetType="{x:Type CheckBox}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}" />
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<ControlTemplate.Resources>
<Storyboard x:Key="OnChecking">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="slider" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
<SplineDoubleKeyFrame KeyTime="00:00:00.1000000" Value="53" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="OnUnchecking">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="slider" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
<SplineDoubleKeyFrame KeyTime="00:00:00.1000000" Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
<DockPanel x:Name="dockPanel">
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" ContentTemplate="{TemplateBinding ContentTemplate}" RecognizesAccessKey="True" VerticalAlignment="Center" />
<Grid>
<Border x:Name="BackgroundBorder" BorderBrush="#FF939393" BorderThickness="1" CornerRadius="3" Height="27" Width="94">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#FFB5B5B5" Offset="0" />
<GradientStop Color="#FFDEDEDE" Offset="0.1" />
<GradientStop Color="#FFEEEEEE" Offset="0.5" />
<GradientStop Color="#FFFAFAFA" Offset="0.5" />
<GradientStop Color="#FFFEFEFE" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition /><ColumnDefinition />
</Grid.ColumnDefinitions>
<Ellipse x:Name="Off" Width="14" Height="14" Stroke="#FF7A7A7A" StrokeThickness="2" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" />
<Line x:Name="On" X1="0" Y1="0" X2="0" Y2="14" Stroke="#FF7A7A7A" StrokeThickness="2" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</Border>
<Border BorderBrush="#FF939393" HorizontalAlignment="Left" x:Name="slider" Width="41" Height="27" BorderThickness="1" CornerRadius="3" RenderTransformOrigin="0.5,0.5" Margin="0">
<Border.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1" ScaleY="1" />
<SkewTransform AngleX="0" AngleY="0" />
<RotateTransform Angle="0" />
<TranslateTransform X="0" Y="0" />
</TransformGroup>
</Border.RenderTransform>
<Border.Background>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFF0F0F0" Offset="0" />
<GradientStop Color="#FFCDCDCD" Offset="0.1" />
<GradientStop Color="#FFFBFBFB" Offset="1" />
</LinearGradientBrush>
</Border.Background>
</Border>
</Grid>
</DockPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource OnUnchecking}" x:Name="OnUnchecking_BeginStoryboard" />
</Trigger.ExitActions>
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource OnChecking}" x:Name="OnChecking_BeginStoryboard" />
</Trigger.EnterActions>
<Setter TargetName="On" Property="Stroke" Value="White" />
<Setter TargetName="Off" Property="Stroke" Value="White" />
<!-- Change Orange or Blue color here -->
<Setter TargetName="BackgroundBorder" Property="Background" Value="{StaticResource CheckedOrange}" />
<Setter TargetName="BackgroundBorder" Property="BorderBrush" Value="{StaticResource CheckedOrangeBorder}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<!-- ToDo: Add Style for Isenabled == False -->
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
A few open source ToggleSwitches:
ToggleSwitch looks good, available by NuGet, too.
MahApps ToggleSwitch is a part of bigger MahApps library of Metro like controls.
I just posted an entry in regards to this which provides a proper sliding action, full configurability and doesn't require to be a fixed size (got annoyed as I couldn't find anything on the web that provided a solution like that).
You can find it here: http://itsallaboutthexaml.blogspot.com/2012/01/variables-in-animation.html
Well I set out to accomplish this same task but the examples fell a little short of production code. For instance what happens if you put text into the control like On/Off or a localized version of the text, answer is you have to define the size of the control because you cannot modify an animation or template triggers after you have rendered the control. This gives you a one-size-fits-all solution that will not work with localized text.
My solution was to create the template for the control dynamically using the control's Loaded event and the FrameworkElementFactory class. I have to say it was by far complicated but could be achieved. Simply put, in your code behind, create a template as described, setup dependency properties for your on/off text, use the text metrics to determine the control's width, height and animation values.
I'm sorry that I cannot post the solution since it belongs to Avanquest now. :(
Look for it in SystemSuite and Fix-It 12.
I like the nice prototype from arconaut and I added some code to get the border rounded.
You have to remove the "Background" property from the Grid declaration and add this lines between the Grid declaration and the first TextBlock declaration:
<Border
x:Name="back"
CornerRadius="3,3,3,3"
BorderThickness="1"
BorderBrush="#FFC0CCD9"
>
<Rectangle Fill="#FFC0CCD9"/>
</Border>

Resources