Ползунок Включение / выключение в WPF - PullRequest
28 голосов
/ 15 мая 2009

Я ищу учебник WPF по созданию ползункового переключателя ВКЛ / ВЫКЛ, как на iPhone.

Вот пример (опция «Отправить весь трафик») https://secure -tunnel.com / support / software_setup / iphone / images / iphone_vpn_settings.jpg

Есть идеи?

Ура, Кевин.

Ответы [ 6 ]

80 голосов
/ 15 мая 2009

Я не видел учебник по этой конкретной проблеме, но я думаю, вы можете начать с запуска Expression Blend и установки CheckBox на него. Затем выберите CheckBox, перейдите в главное меню - Объект -> Редактировать стиль -> Редактировать копию

Это заставит Blend сгенерировать стиль CheckBox по умолчанию, чтобы вы могли изменить его. Посмотрите, как там все работает, и вы сможете достичь некоторых результатов.

По сути (помимо цветов и кистей) вам нужно взглянуть на триггеры, подключенные к свойству IsChecked. Например. когда IsChecked - True, вы перемещаете прямоугольник в одну из сторон, показывает слово ON и скрываете слово OFF. Чтобы анимировать это, вам нужно всего лишь добавить анимацию триггера.

UPD: Я потратил 10-15 минут в смеси, чтобы сделать «прототип»:

<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>

Я также предлагаю вам прочитать о стилях и шаблонах в WPF, если вам интересно.

50 голосов
/ 18 марта 2011

Я создал несколько стилей на основе поста arconaut оранжевого и синего цвета.

Снимок экрана: click

Я хотел, чтобы мой стиль ближе соответствовал стилю включения / выключения на устройствах iOS. Одно из отличий этого стиля заключается в том, что скользящая анимация перемещает только переключатель, а не индикаторы ниже. Может быть, если я найду время, я изменю его таким образом. До тех пор я хочу поделиться своим результатом. Это не идеально, но вот код.

<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>
9 голосов
/ 20 мая 2015

Несколько ToggleSwitches с открытым исходным кодом:

  • ToggleSwitch выглядит хорошо, доступно и в NuGet.
  • MahApps ToggleSwitch является частью большой библиотеки MahApps с элементами управления в стиле Metro.
3 голосов
/ 03 января 2012

Я только что опубликовал запись, касающуюся этого, которая обеспечивает правильное скользящее действие, полную конфигурируемость и не требует фиксированного размера (раздражало, что я не смог найти в Интернете ничего, что предоставило бы подобное решение) ).

Вы можете найти его здесь: http://itsallaboutthexaml.blogspot.com/2012/01/variables-in-animation.html

Знайте, что уже поздно отвечать на этот вопрос, но надеюсь, что это поможет кому-нибудь в будущем.

1 голос
/ 01 мая 2012

Что ж, я решил выполнить ту же задачу, но примеры немного не соответствовали производственному коду. Например, что произойдет, если вы поместите текст в элемент управления, такой как «Вкл. / Выкл.» Или в локализованную версию текста, ответ заключается в том, что вы должны определить размер элемента управления, поскольку вы не можете изменить анимацию или триггеры шаблона после того, как вы представили элемент управления. Это дает вам универсальное решение, которое не будет работать с локализованным текстом.

Моим решением было создание шаблона для элемента управления динамически с использованием события Loaded элемента управления и класса FrameworkElementFactory. Я должен сказать, что это было намного сложнее, но могло быть достигнуто. Проще говоря, в своем коде создайте шаблон, как описано, настройте свойства зависимостей для текста включения / выключения, используйте текстовые метрики для определения ширины, высоты и значений анимации элемента управления.

Извините, что не могу опубликовать решение, поскольку оно теперь принадлежит Avanquest. (

Ищите его в SystemSuite и Fix-It 12.

0 голосов
/ 20 октября 2010

Мне нравится хороший прототип от arconaut, и я добавил немного кода для округления границы.

Вы должны удалить свойство «Background» из объявления Grid и добавить эти строки между объявлением Grid и первым объявлением TextBlock:

<Border
    x:Name="back"
    CornerRadius="3,3,3,3"
    BorderThickness="1"
    BorderBrush="#FFC0CCD9"
    >
    <Rectangle Fill="#FFC0CCD9"/>
</Border>
...