月更
This commit is contained in:
136
AntDesignWPF/Controls/Switch/Switch.cs
Normal file
136
AntDesignWPF/Controls/Switch/Switch.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
|
||||
namespace AntDesignWPF.Controls
|
||||
{
|
||||
[TemplatePart(Name = PART_Dot, Type = typeof(FrameworkElement))]
|
||||
public class Switch : ToggleButton
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private const string PART_Dot = "PART_Dot";
|
||||
|
||||
private FrameworkElement dot;
|
||||
|
||||
private VisualState pressedState;
|
||||
|
||||
private Storyboard pressedStoryboard;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public static readonly DependencyProperty LoadingProperty =
|
||||
DependencyProperty.Register("Loading", typeof(bool), typeof(Switch), new PropertyMetadata(false));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets loading state of switch.
|
||||
/// </summary>
|
||||
public bool Loading
|
||||
{
|
||||
get { return (bool)GetValue(LoadingProperty); }
|
||||
set { SetValue(LoadingProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SizeProperty =
|
||||
DependencyProperty.Register("Size", typeof(Sizes?), typeof(Switch), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the size of the switch.
|
||||
/// </summary>
|
||||
public Sizes? Size
|
||||
{
|
||||
get { return (Sizes?)GetValue(SizeProperty); }
|
||||
set { SetValue(SizeProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty UnCheckedContentProperty =
|
||||
DependencyProperty.Register("UnCheckedContent", typeof(object), typeof(Switch), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets content to be shown when the state is unchecked.
|
||||
/// </summary>
|
||||
public object UnCheckedContent
|
||||
{
|
||||
get { return GetValue(UnCheckedContentProperty); }
|
||||
set { SetValue(UnCheckedContentProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
static Switch()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(Switch), new FrameworkPropertyMetadata(typeof(Switch)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
dot = GetTemplateChild(PART_Dot) as FrameworkElement;
|
||||
pressedState = GetTemplateChild("Pressed") as VisualState;
|
||||
|
||||
if (pressedState != null && pressedState.Storyboard != null)
|
||||
{
|
||||
pressedStoryboard = pressedState.Storyboard.Clone();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
|
||||
{
|
||||
base.OnRenderSizeChanged(sizeInfo);
|
||||
SetDotAnimation();
|
||||
}
|
||||
private bool DotAnimated = false;
|
||||
protected override void OnIsPressedChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnIsPressedChanged(e);
|
||||
//if (!DotAnimated)
|
||||
//{
|
||||
if (dot != null /*&& IsChecked.HasValue && IsChecked.Value*/ && IsPressed)
|
||||
{
|
||||
var to = dot.Margin;
|
||||
// to.Left -= dot.ActualWidth * 1.3333 - dot.ActualWidth;
|
||||
to.Right -= dot.ActualWidth * 1.3333 - dot.ActualWidth;
|
||||
var ease = new CircleEase() { EasingMode = EasingMode.EaseInOut };
|
||||
var animation = new ThicknessAnimation(to, TimeSpan.FromSeconds(0.36)) { EasingFunction = ease };
|
||||
|
||||
dot.BeginAnimation(MarginProperty, animation);
|
||||
}
|
||||
|
||||
//else if (!IsPressed) DotAnimated = false;
|
||||
//}
|
||||
}
|
||||
|
||||
private void SetDotAnimation()
|
||||
{
|
||||
if (dot == null || pressedState == null || DotAnimated) return;
|
||||
|
||||
DotAnimated = true;
|
||||
var storyboard = pressedStoryboard != null ? pressedStoryboard.Clone() : new Storyboard();
|
||||
var ease = new CircleEase() { EasingMode = EasingMode.EaseInOut };
|
||||
var animation = new DoubleAnimation(dot.ActualWidth * 1.3333, TimeSpan.FromSeconds(0.36)) { EasingFunction = ease };
|
||||
|
||||
Storyboard.SetTargetName(animation, PART_Dot);
|
||||
Storyboard.SetTargetProperty(animation, new PropertyPath("Width"));
|
||||
|
||||
storyboard.Children.Add(animation);
|
||||
pressedState.Storyboard = storyboard;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
190
AntDesignWPF/Controls/Switch/Switch.xaml
Normal file
190
AntDesignWPF/Controls/Switch/Switch.xaml
Normal file
@@ -0,0 +1,190 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:controls="clr-namespace:AntDesignWPF.Controls"
|
||||
xmlns:helpers="clr-namespace:AntDesignWPF.Helpers"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/AntDesignWPF;component/Themes/Converters.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/AntDesignWPF;component/Themes/Animations.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<Style x:Key="Ant.SwitchFocusVisualStyle">
|
||||
<Setter Property="Control.Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Control}">
|
||||
<Border
|
||||
BorderBrush="{DynamicResource AntDesign.Brush.Primary}"
|
||||
BorderThickness="2.5"
|
||||
CornerRadius="{Binding ActualHeight, Mode=OneWay, RelativeSource={RelativeSource Self}, Converter={StaticResource DoubleToCornerRadiusConverter}, ConverterParameter=2}"
|
||||
Margin="-2"
|
||||
Opacity="0.2" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="{x:Type controls:Switch}">
|
||||
<Setter Property="MinWidth" Value="44" />
|
||||
<Setter Property="Padding" Value="6,0" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
<Setter Property="Height" Value="{DynamicResource SwitchHeight}" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource FontSizeSmall}" />
|
||||
<Setter Property="Background" Value="{DynamicResource AntDesign.Brush.TextQuaternary}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource AntDesign.Brush.TextOnPrimary}" />
|
||||
<Setter Property="FocusVisualStyle" Value="{StaticResource Ant.SwitchFocusVisualStyle}" />
|
||||
<Setter Property="helpers:AntControl.CornerRadius" Value="{Binding Height, Mode=OneWay, RelativeSource={RelativeSource Self}, Converter={StaticResource DoubleToCornerRadiusConverter}, ConverterParameter=2}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type controls:Switch}">
|
||||
<Grid>
|
||||
<!-- Effect -->
|
||||
<Border
|
||||
BorderBrush="{DynamicResource AntDesign.Brush.Primary}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="{Binding CornerRadius, Mode=OneWay, ElementName=Border}"
|
||||
Focusable="False"
|
||||
Margin="-1"
|
||||
Opacity="0.4"
|
||||
x:Name="Effect" />
|
||||
<!-- Border -->
|
||||
<Border
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="{Binding Path=(helpers:AntControl.CornerRadius), Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
x:Name="Border" />
|
||||
<!-- Content -->
|
||||
<ContentPresenter
|
||||
Content="{TemplateBinding UnCheckedContent}"
|
||||
ContentStringFormat="{TemplateBinding ContentStringFormat}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="{TemplateBinding Padding}"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
x:Name="Content" />
|
||||
<!-- Dot -->
|
||||
<Border
|
||||
Background="{TemplateBinding Foreground}"
|
||||
CornerRadius="{Binding Height, Mode=OneWay, RelativeSource={RelativeSource Self}, Converter={StaticResource DoubleToCornerRadiusConverter}, ConverterParameter=2}"
|
||||
Focusable="False"
|
||||
Height="{Binding Height, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource SubtractionConverter}, ConverterParameter=4}"
|
||||
HorizontalAlignment="Left"
|
||||
RenderTransformOrigin="0,0"
|
||||
VerticalAlignment="Center"
|
||||
Width="{Binding Height, Mode=OneWay, RelativeSource={RelativeSource Self}}"
|
||||
x:Name="PART_Dot">
|
||||
<Border.Margin>
|
||||
<MultiBinding Converter="{StaticResource DoubleToThicknessMultiConverter}" ConverterParameter="2">
|
||||
<Binding
|
||||
Mode="OneWay"
|
||||
Path="ActualWidth"
|
||||
RelativeSource="{RelativeSource TemplatedParent}" />
|
||||
<Binding
|
||||
Mode="OneWay"
|
||||
Path="Height"
|
||||
RelativeSource="{RelativeSource Self}" />
|
||||
</MultiBinding>
|
||||
</Border.Margin>
|
||||
<Border.Effect>
|
||||
<DropShadowEffect
|
||||
BlurRadius="4"
|
||||
Color="#005317"
|
||||
Direction="270"
|
||||
Opacity="0.2"
|
||||
ShadowDepth="1" />
|
||||
</Border.Effect>
|
||||
<controls:Icon
|
||||
Foreground="{DynamicResource AntDesign.Brush.TextPrimary}"
|
||||
Type="loading"
|
||||
Visibility="{Binding Loading, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
x:Name="Icon" />
|
||||
</Border>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualStateGroup.Transitions>
|
||||
<VisualTransition From="Pressed">
|
||||
<Storyboard>
|
||||
<ThicknessAnimation
|
||||
Duration="0:0:0.36"
|
||||
EasingFunction="{StaticResource EaseInOutCirc}"
|
||||
Storyboard.TargetName="PART_Dot"
|
||||
Storyboard.TargetProperty="Margin" />
|
||||
<DoubleAnimation
|
||||
Duration="0:0:0.36"
|
||||
EasingFunction="{StaticResource EaseInOutCirc}"
|
||||
Storyboard.TargetName="PART_Dot"
|
||||
Storyboard.TargetProperty="Width" />
|
||||
</Storyboard>
|
||||
</VisualTransition>
|
||||
</VisualStateGroup.Transitions>
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="MouseOver" />
|
||||
<VisualState x:Name="Pressed" />
|
||||
<VisualState x:Name="Disabled" />
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="CheckStates">
|
||||
<VisualState x:Name="Checked">
|
||||
<Storyboard>
|
||||
<ThicknessAnimation
|
||||
Duration="0:0:0.36"
|
||||
EasingFunction="{StaticResource EaseInOutCirc}"
|
||||
Storyboard.TargetName="PART_Dot"
|
||||
Storyboard.TargetProperty="(FrameworkElement.Margin)" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Unchecked">
|
||||
<Storyboard>
|
||||
<ThicknessAnimation
|
||||
Duration="0:0:0.36"
|
||||
EasingFunction="{StaticResource EaseInOutCirc}"
|
||||
Storyboard.TargetName="PART_Dot"
|
||||
Storyboard.TargetProperty="(FrameworkElement.Margin)"
|
||||
To="3 0 0 0" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Indeterminate" />
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsChecked" Value="True">
|
||||
<Setter Property="HorizontalAlignment" TargetName="Content" Value="Left" />
|
||||
<Setter Property="RenderTransformOrigin" TargetName="PART_Dot" Value="1,0" />
|
||||
<Setter Property="Foreground" TargetName="Icon" Value="{DynamicResource AntDesign.Brush.Primary}" />
|
||||
<Setter Property="Background" TargetName="Border" Value="{DynamicResource AntDesign.Brush.Primary}" />
|
||||
<Setter Property="Content" TargetName="Content" Value="{Binding Content, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" />
|
||||
</Trigger>
|
||||
<Trigger Property="Size" Value="Small">
|
||||
<Setter Property="RenderTransform" TargetName="Icon">
|
||||
<Setter.Value>
|
||||
<ScaleTransform ScaleX="0.75" ScaleY="0.75" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="Spin" TargetName="Icon" Value="True" />
|
||||
</Trigger>
|
||||
<EventTrigger RoutedEvent="ButtonBase.Click">
|
||||
<BeginStoryboard Storyboard="{StaticResource Ant.ClickAnimating}" />
|
||||
</EventTrigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="Loading" Value="True">
|
||||
<Setter Property="IsEnabled" Value="False" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Opacity" Value="{DynamicResource SwitchDisabledOpacity}" />
|
||||
</Trigger>
|
||||
<Trigger Property="Size" Value="Small">
|
||||
<Setter Property="Padding" Value="3,0" />
|
||||
<Setter Property="MinWidth" Value="28" />
|
||||
<Setter Property="Height" Value="{DynamicResource SwitchHeightSmall}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
Reference in New Issue
Block a user