views:

1185

answers:

2

Hi,

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

Any ideas?

Cheers, Kevin.

+9  A: 

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.

arconaut
Would a two value (0 and 1) slider not work?Maybe style the slide to a block half the width and the full hight of the control. 0 = OFF, 1 = ON. just a case of getting the text behind the slider. Only thinking this as the slide animation I assume would be easier to achieve.Please bare in mind I am very much a newbie and have not idea how to do what I just said :-)Kevin.
Kevin Preston
i think checkbox is better because it IS the control that can have two states ON and OFF (actually there's also NULL, but we're not interested in it now :) ). But how these ON and OFF look is irrelevant. That's the idea of templating in WPF.
arconaut
I suppose the reason I was suggesting the slider was its the closest visually to what I want to achieve and it does contain the functionality, albeit slightly differently to the checkbox, that I need. I looked that the checkbox style template and was quite daunting when trying to figure out what to change to get this slider effect.
Kevin Preston
Cheers, I will have a play with your prototype. I have been reading through MS documentation.Thanks for your help.
Kevin Preston
<selfishness=on>don't forget to vote up and accept if it answers your question<selfishness=off> :)
arconaut
Cant vote up yetNeed more points or something. But big Kudos to you for taking the time to help me. It is truly appreciated.
Kevin Preston
A: 

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"

>

unexpectedkas