wpf WPF中的滑块开/关开关

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/865767/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 20:26:16  来源:igfitidea点击:

Slider On/Off Switch in WPF

wpfwpf-controls

提问by Kevin Preston

I am looking for a WPF tutorial on creating a slide ON/OFF switch like on the iPhone.

我正在寻找有关在 iPhone 上创建滑动开/关开关的 WPF 教程。

Here is an example (the "Send all traffic" option) https://secure-tunnel.com/support/software_setup/iphone/images/iphone_vpn_settings.jpg

这是一个示例(“发送所有流量”选项)https://secure-tunnel.com/support/software_setup/iphone/images/iphone_vpn_settings.jpg

Any ideas?

有任何想法吗?

Cheers, Kevin.

干杯,凯文。

回答by arconaut

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

我还没有看到有关这个确切问题的教程,但我想您可以先启动 Expression Blend 并在其上放置一个 CheckBox。然后选择复选框,转到主菜单 - 对象 -> 编辑样式 -> 编辑副本

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.

这将使 Blend 生成 CheckBox 的默认样式,以便您可以对其进行修改。看看那里是如何运作的,你将能够取得一些成果。

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.

基本上(除了颜色和画笔的东西),您需要查看与 IsChecked 属性相关联的触发器。例如,当 IsChecked 为 True 时,您将矩形移动到一侧,显示 ON 字并隐藏 OFF 字。要设置动画,您只需要添加触发器输入和输出动画。

UPD: I've spent 10-15 minutes in blend to make a "prototype":

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>

I'm also suggesting you to read about Styles and Templates in WPF if you're interested.

如果您有兴趣,我还建议您阅读 WPF 中的样式和模板。

回答by Timo

I created some styles based on the post by arconaut in orange and blue.

我根据 arconaut 的帖子创建了一些橙色和蓝色的样式。

Screenshot: click

截屏: 点击

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.

我希望我的风格更接近 iOS 设备的 On/Off Switch 风格。这种风格的一个区别是,滑动动画只滑动开关而不是下面的指示器。也许如果我能找到一些时间,我会这样修改它。在那之前,我想分享我的结果。它并不完美,但这是代码。

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

回答by xmedeko

A few open source ToggleSwitches:

一些开源的 ToggleSwitches:

回答by Iain Skett

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

你可以在这里找到它:http: //itsallaboutthexaml.blogspot.com/2012/01/variables-in-animation.html

Know it's late in answering this question, but hope it helps anyone in the future.

知道回答这个问题为时已晚,但希望它可以帮助将来的任何人。

回答by K. Rodgers

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.

好吧,我开始完成同样的任务,但示例中缺少生产代码。例如,如果您将文本放入控件中(如 On/Off 或文本的本地化版本)会发生什么,答案是您必须定义控件的大小,因为在呈现控件后您无法修改动画或模板触发器。这为您提供了一种适用于本地化文本的通用解决方案。

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.

我的解决方案是使用控件的 Loaded 事件和 FrameworkElementFactory 类动态地为控件创建模板。我不得不说这很复杂,但可以实现。简单地说,在你的代码后面,按照描述创建一个模板,为你的开/关文本设置依赖属性,使用文本度量来确定控件的宽度、高度和动画值。

I'm sorry that I cannot post the solution since it belongs to Avanquest now. :(

很抱歉我不能发布解决方案,因为它现在属于 Avanquest。:(

Look for it in SystemSuite and Fix-It 12.

在 SystemSuite 和 Fix-It 12 中查找它。

回答by JoanComasFdz

I like the nice prototype from arconaut and I added some code to get the border rounded.

我喜欢来自 arconaut 的漂亮原型,我添加了一些代码来使边框变圆。

You have to remove the "Background" property from the Grid declaration and add this lines between the Grid declaration and the first TextBlock declaration:

您必须从 Grid 声明中删除“Background”属性,并在 Grid 声明和第一个 TextBlock 声明之间添加以下行:

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