Add project files.
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF.Controls;
|
||||
|
||||
public class Countdown : Control
|
||||
{
|
||||
public static readonly DependencyProperty CountdownIdentifierProperty =
|
||||
DependencyProperty.Register(nameof(CountdownIdentifier),
|
||||
typeof(CountdownIdentifier), typeof(Countdown));
|
||||
|
||||
private Storyboard? completingTransition;
|
||||
private VisualStateGroup? countdownGroup;
|
||||
private bool isTransitioning;
|
||||
|
||||
public Countdown()
|
||||
{
|
||||
DefaultStyleKey = typeof(Countdown);
|
||||
}
|
||||
|
||||
public event TypedEventHandler<Countdown, CountdownCompletedEventArgs>? Completed;
|
||||
|
||||
public event TypedEventHandler<Countdown, CountdownStartedEventArgs>? Started;
|
||||
|
||||
public CountdownIdentifier CountdownIdentifier
|
||||
{
|
||||
get => (CountdownIdentifier)GetValue(CountdownIdentifierProperty);
|
||||
set => SetValue(CountdownIdentifierProperty, value);
|
||||
}
|
||||
|
||||
private Storyboard? CompletingTransition
|
||||
{
|
||||
get => completingTransition;
|
||||
set
|
||||
{
|
||||
if (completingTransition is not null)
|
||||
{
|
||||
CompletingTransition!.Completed -= OnTransitionCompleted;
|
||||
}
|
||||
|
||||
completingTransition = value;
|
||||
|
||||
if (completingTransition is not null)
|
||||
{
|
||||
CompletingTransition!.Completed += OnTransitionCompleted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (GetTemplateChild("Container") is Grid container)
|
||||
{
|
||||
countdownGroup = ((IEnumerable<VisualStateGroup>)VisualStateManager.GetVisualStateGroups(container))!.FirstOrDefault(x => x.Name == "CountdownStates");
|
||||
}
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (isTransitioning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Started?.Invoke(this, new CountdownStartedEventArgs());
|
||||
|
||||
isTransitioning = true;
|
||||
CompletingTransition = GetTransitionStoryboardByName($"{CountdownIdentifier}");
|
||||
VisualStateManager.GoToState(this, $"{CountdownIdentifier}", true);
|
||||
}
|
||||
|
||||
private Storyboard GetTransitionStoryboardByName(string transitionName)
|
||||
{
|
||||
if (countdownGroup is not null)
|
||||
{
|
||||
if (((IEnumerable<VisualState>)countdownGroup.States).Where(x => x.Name == transitionName).Select(x => x.Storyboard).FirstOrDefault() is Storyboard transition)
|
||||
{
|
||||
return transition;
|
||||
}
|
||||
}
|
||||
|
||||
return new Storyboard();
|
||||
}
|
||||
|
||||
private void OnTransitionCompleted(object? sender, EventArgs args)
|
||||
{
|
||||
CompletingTransition!.Completed -= OnTransitionCompleted;
|
||||
VisualStateManager.GoToState(this, "Pending", false);
|
||||
|
||||
isTransitioning = false;
|
||||
|
||||
Completed?.Invoke(this, new CountdownCompletedEventArgs());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:TheXamlGuy.UI.WPF.Controls">
|
||||
<Style TargetType="controls:Countdown">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="controls:Countdown">
|
||||
<Grid x:Name="Container">
|
||||
<Grid
|
||||
x:Name="TextRoot"
|
||||
Opacity="0"
|
||||
RenderTransformOrigin="0.5,0.5">
|
||||
<TextBlock x:Name="TextBlock" />
|
||||
<Grid.RenderTransform>
|
||||
<ScaleTransform x:Name="ScaleTransform" />
|
||||
</Grid.RenderTransform>
|
||||
</Grid>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CountdownStates">
|
||||
<VisualState x:Name="Pending" />
|
||||
<VisualState x:Name="TenSecond">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextBlock" Storyboard.TargetProperty="(TextBlock.Text)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="10" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:01" Value="9" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:02" Value="8" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:03" Value="7" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:04" Value="6" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:05" Value="5" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:06" Value="4" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:07" Value="3" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:08" Value="2" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:09" Value="1" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:10" Value="1" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames
|
||||
RepeatBehavior="10x"
|
||||
Storyboard.TargetName="TextRoot"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)">
|
||||
<LinearDoubleKeyFrame KeyTime="0" Value="0.0" />
|
||||
<LinearDoubleKeyFrame KeyTime="00:00:00.167" Value="1.0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:01" Value="1.0" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames
|
||||
RepeatBehavior="10x"
|
||||
Storyboard.TargetName="ScaleTransform"
|
||||
Storyboard.TargetProperty="ScaleX">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="1.5" />
|
||||
<SplineDoubleKeyFrame
|
||||
KeySpline="0,0,0,1"
|
||||
KeyTime="00:00:00.250"
|
||||
Value="1.0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:01" Value="1.0" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames
|
||||
RepeatBehavior="10x"
|
||||
Storyboard.TargetName="ScaleTransform"
|
||||
Storyboard.TargetProperty="ScaleY">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="1.5" />
|
||||
<SplineDoubleKeyFrame
|
||||
KeySpline="0,0,0,1"
|
||||
KeyTime="00:00:00.250"
|
||||
Value="1.0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:01" Value="1.0" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="FiveSecond">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextBlock" Storyboard.TargetProperty="(TextBlock.Text)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="5" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:01" Value="4" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:02" Value="3" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:03" Value="2" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:04" Value="1" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames
|
||||
RepeatBehavior="5x"
|
||||
Storyboard.TargetName="TextRoot"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)">
|
||||
<LinearDoubleKeyFrame KeyTime="0" Value="0.0" />
|
||||
<LinearDoubleKeyFrame KeyTime="00:00:00.167" Value="1.0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:01" Value="1.0" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames
|
||||
RepeatBehavior="5x"
|
||||
Storyboard.TargetName="ScaleTransform"
|
||||
Storyboard.TargetProperty="ScaleX">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="1.5" />
|
||||
<SplineDoubleKeyFrame
|
||||
KeySpline="0,0,0,1"
|
||||
KeyTime="00:00:00.250"
|
||||
Value="1.0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:01" Value="1.0" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames
|
||||
RepeatBehavior="5x"
|
||||
Storyboard.TargetName="ScaleTransform"
|
||||
Storyboard.TargetProperty="ScaleY">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="1.5" />
|
||||
<SplineDoubleKeyFrame
|
||||
KeySpline="0,0,0,1"
|
||||
KeyTime="00:00:00.250"
|
||||
Value="1.0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:01" Value="1.0" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="TwoSecond">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextBlock" Storyboard.TargetProperty="(TextBlock.Text)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="2" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:01" Value="1" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames
|
||||
RepeatBehavior="2x"
|
||||
Storyboard.TargetName="TextRoot"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)">
|
||||
<LinearDoubleKeyFrame KeyTime="0" Value="0.0" />
|
||||
<LinearDoubleKeyFrame KeyTime="00:00:00.167" Value="1.0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:01" Value="1.0" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames
|
||||
RepeatBehavior="2x"
|
||||
Storyboard.TargetName="ScaleTransform"
|
||||
Storyboard.TargetProperty="ScaleX">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="1.5" />
|
||||
<SplineDoubleKeyFrame
|
||||
KeySpline="0,0,0,1"
|
||||
KeyTime="00:00:00.250"
|
||||
Value="1.0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:01" Value="1.0" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames
|
||||
RepeatBehavior="2x"
|
||||
Storyboard.TargetName="ScaleTransform"
|
||||
Storyboard.TargetProperty="ScaleY">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="1.5" />
|
||||
<SplineDoubleKeyFrame
|
||||
KeySpline="0,0,0,1"
|
||||
KeyTime="00:00:00.250"
|
||||
Value="1.0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:01" Value="1.0" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,7 @@
|
||||
using System;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF.Controls;
|
||||
public class CountdownCompletedEventArgs : EventArgs
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace TheXamlGuy.UI.WPF.Controls;
|
||||
|
||||
public enum CountdownIdentifier
|
||||
{
|
||||
TenSecond,
|
||||
FiveSecond,
|
||||
TwoSecond
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF.Controls;
|
||||
|
||||
public class CountdownStartedEventArgs : EventArgs
|
||||
{
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user