{A}
{A2的}介绍
这是在WPFSpark系列的第二篇文章。 {A3的}是在CodePlex上的开源项目,其中包含了用户使用的控制,可以由开发者社区图书馆。我正打算写这篇文章,在几个星期前,但我忙于创建几个更令人振奋的控制为WPFSpark库。我将在我即将出版的文章描述这些控件。
在这篇文章中,我在这个库中,我已经开发的第二个控制详细描述。它被称为"ToggleSwitch控制和从ToggleButton的派生,并提供丰富的用户体验。它支持只有两种状态:True或False。
{S}
在以前的WPFSpark系列文章,可以访问这里:{A4纸}背景切换按钮
System.Windows.Controls.Primitives.ToggleButton"是控制,可以切换状态,如CheckBox的基类。它支持三种状态:true,false和null。
{S2的}FluidMoveBehavior
钻研之前到的ToggleSwitch的细节,一个WPF功能(其中扮演了重要的作用,在ToggleSwitch控制)需要提及 - FluidMoveBehavior。 FluidMoveBehavior是Expression Blend的功能,让您的动画元素的位置的变化。动画看起来非常现实的,因为它允许使用EasingFunctions。这里有一个更为详细的描述FluidMoveBehavior的几个环节:{A5的}{A6的}{A7的}ToggleSwitch控制揭秘简单ToggleSwitch
的ToggleSwitch控制,我创建的第一个版本是简单ToggleSwitch控制。为了创建它,我定义的切换按钮,其中有两列和单列组成的网格自定义模板。
{S3的}
第一列(栏)包含一个TextBlock这会定义为选中状态的文本。同样,第二列(列1)包含TextBlock的文本将定义为Unchecked状态。
{四至}
此外,模板还包含边框描绘的ToggleSwitch的拇指。拇指的位置,在网格,将是第一或第二列根据的ToggleSwitch是否在检查或Unchecked状态。
{五}
{六}
的FluidMoveBehavior添加到网格中,将确保无论何时将动画,而不是瞬间的ToggleSwitch变化,一列从拇指到其他的运动状态。 (你应该添加Microsoft.Expression.Interactions.dll和System.Windows.Interactivity.dll引用到您的项目得到FluidMoveBehaviour。)
这里是的简单ToggleSwitch控制模板:
复杂ToggleSwitch<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:System.Windows.Interactivity;
assembly=System.Windows.Interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions">
<Style x:Key="ToggleSwitchStyle"
TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<ControlTemplate.Resources>
<Storyboard x:Key="Timeline1">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="Glow"
Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="00:00:00.4000000"
Value="1" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Timeline2">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="Glow"
Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="00:00:00.4000000"
Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
<Grid MinWidth="120"
MinHeight="40"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
Background="Black">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<i:Interaction.Behaviors>
<ei:FluidMoveBehavior AppliesTo="Children"
Duration="0:0:0.25">
<ei:FluidMoveBehavior.EaseX>
<SineEase EasingMode="EaseIn" />
</ei:FluidMoveBehavior.EaseX>
</ei:FluidMoveBehavior>
</i:Interaction.Behaviors>
<Border Grid.ColumnSpan="2"
BorderBrush="LightGray"
Background="Transparent"
CornerRadius="6"
BorderThickness="1"></Border>
<TextBlock x:Name="OffText"
Grid.Column="0"
HorizontalAlignment="Center"
Text="Debug"
FontFamily="/CvisBuilder;Component/Resources/Font/#Segoe WP"
FontWeight="Light"
VerticalAlignment="Center"
Foreground="LawnGreen"
FontSize="{TemplateBinding FontSize}"></TextBlock>
<TextBlock x:Name="OnText"
Grid.Column="1"
HorizontalAlignment="Center"
FontFamily="/CvisBuilder;Component/Resources/Font/#Segoe WP"
FontWeight="Light"
Text="Release"
VerticalAlignment="Center"
Foreground="LawnGreen"
FontSize="{TemplateBinding FontSize}"></TextBlock>
<Border Name="Thumb"
Grid.Column="0"
BorderBrush="White"
BorderThickness="1"
Margin="3"
CornerRadius="4"
Background="#222222">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.507*" />
<RowDefinition Height="0.493*" />
</Grid.RowDefinitions>
<Border Opacity="0"
HorizontalAlignment="Stretch"
x:Name="Glow"
Width="Auto"
Grid.RowSpan="2"
CornerRadius="2">
<Border.Background>
<RadialGradientBrush>
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform ScaleX="1.702"
ScaleY="2.743" />
<SkewTransform AngleX="0"
AngleY="0" />
<RotateTransform Angle="0" />
<TranslateTransform X="-0.368"
Y="-0.152" />
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Color="LawnGreen"
Offset="0" />
<GradientStop Color="#44006400"
Offset="0.75" />
</RadialGradientBrush>
</Border.Background>
</Border>
<Border HorizontalAlignment="Stretch"
Margin="0,0,0,0"
x:Name="shine"
Width="Auto"
CornerRadius="2,2,0,0">
<Border.Background>
<LinearGradientBrush EndPoint="0.494,0.889"
StartPoint="0.494,0.028">
<GradientStop Color="#99FFFFFF"
Offset="0" />
<GradientStop Color="#33FFFFFF"
Offset="1" />
</LinearGradientBrush>
</Border.Background>
</Border>
</Grid>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked"
Value="true">
<Setter Property="Grid.Column"
TargetName="Thumb"
Value="1" />
</Trigger>
<Trigger Property="IsEnabled"
Value="false">
<Setter Property="Opacity"
Value="0.4" />
<Setter TargetName="OffText"
Property="Foreground"
Value="LightGray"></Setter>
<Setter TargetName="OnText"
Property="Foreground"
Value="LightGray"></Setter>
</Trigger>
<Trigger Property="IsPressed"
Value="True">
<Setter Property="Opacity"
TargetName="shine"
Value="0.6" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Trigger.EnterActions>
<BeginStoryboard
Storyboard="{StaticResource Timeline1}" />
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard x:Name="Timeline2_BeginStoryboard"
Storyboard="{StaticResource Timeline2}" />
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
虽然我与简单ToggleSwitch创造的成就感到高兴,我是远远满足。我想使TextBlocks(用于显示这两个国家的ToggleSwitch)出现用拇指沿的ToggleSwitch显得更逼真。我也想通过修改几个属性的ToggleSwitch控制轻松换肤。
要做到这一点,首先要求的是一个圆角的WPF电网。由于电网没有CornerRadius财产,我有其他选择是电网和封装内边框设置为true边境ClipToBounds财产。后来我发现,边境(和所有的装饰)不执行ClipToBounds即使设置为true裁剪。
为此,我写了ClipBorder类。它也允许用户指定不同圆角半径为边界的每个角落。 (有关详细信息,看看我的文章在我的博客 - {A8的。)
现在的ClipBorder封装网格(名为PART_RootGrid),将用于定位的ToggleSwitch的基于其状态的内容。该网格有三列(左,中,和右)。每列的宽度是动态计算的基础上拇指的宽度。
{七}
的ToggleSwitch的的内容是放置另一个网格(名为PART_ContentGrid)。该网格包含5列(左,CenterLeft,中心,CenterRight和右)。
{S8的}
ContentGrid包含以下内容:CheckedBorder - 这个定义,在的ToggleSwitch控件的Checked状态显示背景。它占地左和CentreLeft列。CheckedTextBlock - 这包含在选中状态,显示的文字。它占地左侧立柱。大拇指 - 这包含的拇指的ToggleSwitch控制。它占地的CenterLeft中心,和CenterRight列。UncheckedBorder - 这个定义,在的ToggleSwitch控制Unchecked状态显示的背景。它占据了CentreRight和右列。
UncheckedTextBlock - 这包含Unchecked状态显示的文字。它占据了右侧立柱。
拇指包含另一个网格,其中包含了拇指它提供了一个闪耀的边境。
下面的图片显示的最外层ClipBorder和细节ContentGrid的。
{S9的}
这里是爆炸一个ToggleSwitch控制3D视图使用一个美妙的工具,称为{A9的获得}。
{S10的}
ContentGrid有比RootGrid较大的宽度,但因为二者都在封装在ClipBorder中,外ClipBorder的部分被截断。基于状态的ToggleSwitch(True或False),拇指大小,内的ContentGrid放置的RootGrid列计算。
的ToggleSwitch控制ThumbWidth的依赖项属性的的ToggleSwitch控制总宽度的百分比定义为一个拇指的宽度。它可以从10到90(含)的值。基于上ThumbWidth,计算的RootGrid和ContentGrid每一列的宽度和保证金的ContentGrid。下面的代码显示了计算:{C}
这里是为复杂的ToggleSwitch控制的控制模板:
更新:WPFSpark V1.0<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:System.Windows.Interactivity;
assembly=System.Windows.Interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:wpfspark="clr-namespace:WPFSpark">
<!-- ToggleSwitch Template -->
<ControlTemplate x:Key="{ComponentResourceKey TypeInTargetAssembly=
wpfspark:ToggleSwitch, ResourceId=ToggleSwitchTemplate}"
TargetType="{x:Type wpfspark:ToggleSwitch}">
<ControlTemplate.Resources>
<Storyboard x:Key="BeginGlow">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="Glow"
Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="00:00:00.4000000"
Value="1" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="EndGlow">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="Glow"
Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="00:00:00.4000000"
Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
<!-- Outermost border of the ToggleSwitch -->
<wpfspark:ClipBorder Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
CornerRadius="{Binding Path=CornerRadius,
RelativeSource={RelativeSource
AncestorType={x:Type wpfspark:ToggleSwitch}}}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid Name="PART_RootGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.4*"></ColumnDefinition>
<ColumnDefinition Width="0.2*"></ColumnDefinition>
<ColumnDefinition Width="0.4*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<i:Interaction.Behaviors>
<ei:FluidMoveBehavior AppliesTo="Children"
Duration="0:0:0.2">
<ei:FluidMoveBehavior.EaseX>
<QuarticEase EasingMode="EaseIn" />
</ei:FluidMoveBehavior.EaseX>
</ei:FluidMoveBehavior>
</i:Interaction.Behaviors>
<!-- PART_Content -->
<Border Name="PART_ContentBorder"
Grid.Column="0"
CornerRadius="0"
Background="Transparent"
BorderThickness="0">
<Grid Name="PART_ContentGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.375*"></ColumnDefinition>
<ColumnDefinition Width="0.1*"></ColumnDefinition>
<ColumnDefinition Width="0.05*"></ColumnDefinition>
<ColumnDefinition Width="0.1*"></ColumnDefinition>
<ColumnDefinition Width="0.375*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<!-- Checked State -->
<!-- Background displayed when
the ToggleSwitch is in the Checked State -->
<Border x:Name="CheckedBorder"
Grid.Column="0"
Grid.ColumnSpan="2"
BorderThickness="0"
Margin="0"
CornerRadius="0"
Background="{Binding Path=CheckedBackground,
RelativeSource={RelativeSource
AncestorType={x:Type wpfspark:ToggleSwitch}}}">
</Border>
<!-- Text which is displayed when
the ToggleSwitch is in the Checked State -->
<TextBlock x:Name="CheckedTextBlock"
Grid.Column="0"
Text="{Binding Path=CheckedText,
RelativeSource={RelativeSource
AncestorType={x:Type wpfspark:ToggleSwitch}}}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}"
Foreground="{Binding Path=CheckedForeground,
RelativeSource={RelativeSource
AncestorType={x:Type wpfspark:ToggleSwitch}}}"
></TextBlock>
<!-- Unchecked State -->
<!-- Background displayed when the ToggleSwitch
is in the Unchecked State -->
<Border x:Name="UncheckedBorder"
Grid.Column="3"
Grid.ColumnSpan="2"
BorderThickness="0"
Margin="0"
CornerRadius="0"
Background="{Binding Path=UncheckedBackground,
RelativeSource={RelativeSource
AncestorType={x:Type wpfspark:ToggleSwitch}}}">
</Border>
<!-- Text which is displayed when the ToggleSwitch
is in the Unchecked State -->
<TextBlock x:Name="UncheckedTextBlock"
Grid.Column="4"
Text="{Binding Path=UncheckedText,
RelativeSource={RelativeSource
AncestorType={x:Type wpfspark:ToggleSwitch}}}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}"
Foreground="{Binding Path=UncheckedForeground,
RelativeSource={RelativeSource
AncestorType={x:Type wpfspark:ToggleSwitch}}}">
</TextBlock>
<!-- ToggleSwitch Thumb -->
<wpfspark:ClipBorder x:Name="PART_Thumb"
Grid.Column="1"
Grid.ColumnSpan="3"
Margin="0"
BorderBrush="{Binding Path=ThumbBorderBrush,
RelativeSource={RelativeSource
AncestorType={x:Type wpfspark:ToggleSwitch}}}"
BorderThickness="{Binding Path=ThumbBorderThickness,
RelativeSource={RelativeSource
AncestorType={x:Type wpfspark:ToggleSwitch}}}"
CornerRadius="{Binding Path=ThumbCornerRadius,
RelativeSource={RelativeSource
AncestorType={x:Type wpfspark:ToggleSwitch}}}"
Background="{Binding Path=ThumbBackground,
RelativeSource={RelativeSource
AncestorType={x:Type wpfspark:ToggleSwitch}}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.507*" />
<RowDefinition Height="0.493*" />
</Grid.RowDefinitions>
<Border x:Name="Glow"
Opacity="0"
HorizontalAlignment="Stretch"
Width="Auto"
Grid.RowSpan="2"
CornerRadius="{Binding Path=ThumbCornerRadius,
RelativeSource={RelativeSource
AncestorType=
{x:Type wpfspark:ToggleSwitch}}}">
<Border.Background>
<RadialGradientBrush>
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform ScaleX="1.702"
ScaleY="2.743" />
<SkewTransform AngleX="0"
AngleY="0" />
<RotateTransform Angle="0" />
<TranslateTransform X="-0.368"
Y="-0.152" />
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop
Color="{Binding Path=ThumbGlowColor,
RelativeSource={RelativeSource
AncestorType=
{x:Type wpfspark:ToggleSwitch}}}"
Offset="0.1" />
<GradientStop Color="#44222222"
Offset="0.8" />
</RadialGradientBrush>
</Border.Background>
</Border>
<Border x:Name="Shine"
HorizontalAlignment="Stretch"
Margin="0,0,0,0"
Width="Auto"
CornerRadius="{Binding Path=ThumbShineCornerRadius,
RelativeSource={RelativeSource
AncestorType=
{x:Type wpfspark:ToggleSwitch}}}">
<Border.Background>
<LinearGradientBrush EndPoint="0.494,0.889"
StartPoint="0.494,0.028">
<GradientStop Color="#99FFFFFF"
Offset="0" />
<GradientStop Color="#33FFFFFF"
Offset="1" />
</LinearGradientBrush>
</Border.Background>
</Border>
</Grid>
</wpfspark:ClipBorder>
</Grid>
</Border>
</Grid>
</wpfspark:ClipBorder>
<ControlTemplate.Triggers>
<Trigger Property="ToggleButton.IsChecked"
Value="false">
<Setter Property="Grid.Column"
TargetName="PART_ContentBorder"
Value="{Binding Path=TargetColumnInternal,
RelativeSource={RelativeSource
AncestorType={x:Type wpfspark:ToggleSwitch}}}" />
</Trigger>
<Trigger Property="IsEnabled"
Value="false">
<Setter Property="Opacity"
Value="0.4" />
<Setter TargetName="UncheckedTextBlock"
Property="Foreground"
Value="LightGray"></Setter>
<Setter TargetName="CheckedTextBlock"
Property="Foreground"
Value="LightGray"></Setter>
</Trigger>
<Trigger Property="ToggleButton.IsPressed"
Value="True">
<Setter Property="Opacity"
TargetName="Shine"
Value="0.6" />
</Trigger>
<Trigger Property="ToggleButton.IsMouseOver"
Value="True">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource BeginGlow}" />
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource EndGlow}" />
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style TargetType="{x:Type wpfspark:ToggleSwitch}">
<Setter Property="Template"
Value="{StaticResource {ComponentResourceKey
TypeInTargetAssembly=wpfspark:ToggleSwitch,
ResourceId=ToggleSwitchTemplate}}" />
</Style>
</ResourceDictionary>
随着释放WPFSpark 1.0,已被纳入ToggleSwitch以下变化:新增的IsCheckedLeft依赖属性表明是否检查的内容出现在左侧或右侧的ToggleSwitch。增加时ToggleSwitch处于选中状态,这是显示的CheckedToolTip财产。将此属性设置为String.Empty(""),以防止显示此工具提示。添加时ToggleSwitch Unchecked状态显示UncheckedToolTip财产。将此属性设置为String.Empty(""),以防止显示此工具提示。
退房} {A10的最新的源代码,以获得最新的ToggleSwitch。
ToggleSwitch属性依赖项属性类型描述默认值CheckedBackground刷获取或设置在ToggleSwitch控制CheckedBorder的背景。白CheckedForeground刷获取,或设置的CheckedText的前景色。黑色CheckedText串获取或设置所显示的文本,当ToggleSwitch控制处于选中状态。String.EmptyCheckedToolTip串获取或设置的ToggleSwitch处于选中状态时所显示的工具提示。将此属性设置为String.Empty(""),以防止显示此工具提示。String.EmptyCornerRadiusCornerRadius获取或设置外层ClipBorder CornerRadius。0IsCheckedLeft布尔获取或设置是否检查的内容出现在的ToggleSwitch的左侧或右侧。真TargetColumnInternalINT32获取或设置在的ContentGrid时,必须放置在Unchecked状态ToggleSwitch是RootGrid的列。此属性在内部使用,不应由用户设置。0ThumbBackground获取或设置背景刷拇指。黑色ThumbBorderBrush刷获取或设置的Thumb边框的颜色。灰色ThumbBorderThickness厚度获取或设置的Thumb边框的厚度。ThumbCornerRadiusCornerRadius获取或设置拇指边境CornerRadius。0ThumbGlowColor颜色获取或设置在拇指辉光的颜色,当鼠标悬停。草绿ThumbShineCornerRadiusCornerRadius获取或设置的Thumb边境的光泽CornerRadius。0ThumbWidth双击获取或设置的的ToggleSwitch控制总宽度的百分比拇指的宽度。值范围:10 - 90(含)。40UncheckedBackground刷获取或设置在ToggleSwitch控制UncheckedBorder的背景。
白UncheckedForeground刷获取,或设置的CheckedText的前景色。黑色UncheckedText串获取或设置,当ToggleSwitch控制在Unchecked状态所显示的文本。
String.EmptyUncheckedToolTip串获取或设置当ToggleSwitch Unchecked状态所显示的工具提示。将此属性设置为String.Empty(""),以防止显示此工具提示。String.Empty剥皮ToggleSwitch
您可以通过修改上述的依赖属性的皮肤的ToggleSwitch。你可以修改控制checked和unchecked状态的背景。你甚至可以修改拇指CornerRadius,获得各种拇指形状不等矩形圆角矩形,甚至圈太!
这里是的ToggleSwitch控制各种皮肤的几个例子。
{的S11}端点
如果你想了解WPF中自定义控件开发,我建议你阅读本书由帕Podila的{A11}。这是深深的信息,并含有大量的提示和技巧和其他有趣的事实,关于自定义控件。历史2011年12月21日,:WPFSpark V1.0发布2011年7月31日:WPFSpark V0.6发布| Ratish菲利普