feat: add auto tick sample.

This commit is contained in:
rabbitism
2024-04-22 02:05:29 +08:00
parent 3815a5114c
commit db6ba785dd
4 changed files with 161 additions and 23 deletions

View File

@@ -5,10 +5,14 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:u="https://irihi.tech/ursa" xmlns:u="https://irihi.tech/ursa"
xmlns:vm="clr-namespace:Ursa.Demo.ViewModels"
x:DataType="vm:ClockDemoViewModel"
x:CompileBindings="True"
d:DesignHeight="450" d:DesignHeight="450"
d:DesignWidth="800" d:DesignWidth="800"
mc:Ignorable="d"> mc:Ignorable="d">
<Grid> <Grid>
<u:Clock HorizontalAlignment="Left"></u:Clock> <u:Clock HorizontalAlignment="Left" Time="{Binding Time}"></u:Clock>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@@ -1,6 +1,31 @@
namespace Ursa.Demo.ViewModels; using System;
using System.Timers;
using CommunityToolkit.Mvvm.ComponentModel;
public class ClockDemoViewModel namespace Ursa.Demo.ViewModels;
public partial class ClockDemoViewModel: ObservableObject, IDisposable
{ {
private Timer _timer;
[ObservableProperty] private DateTime _time;
public ClockDemoViewModel()
{
Time = DateTime.Now;
_timer = new Timer(1000);
_timer.Elapsed += TimerOnElapsed;
_timer.Start();
}
private void TimerOnElapsed(object? sender, ElapsedEventArgs e)
{
Time = DateTime.Now;
}
public void Dispose()
{
_timer.Stop();
_timer.Elapsed -= TimerOnElapsed;
_timer.Dispose();
}
} }

View File

@@ -5,15 +5,55 @@
xmlns:u="https://irihi.tech/ursa"> xmlns:u="https://irihi.tech/ursa">
<!-- Add Resources Here --> <!-- Add Resources Here -->
<ControlTheme x:Key="{x:Type u:Clock}" TargetType="u:Clock"> <ControlTheme x:Key="{x:Type u:Clock}" TargetType="u:Clock">
<Setter Property="HandBrush" Value="{DynamicResource SemiGrey6}"/>
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate TargetType="u:Clock"> <ControlTemplate TargetType="u:Clock">
<Grid> <Grid>
<u:ClockTicks HorizontalAlignment="{TemplateBinding HorizontalAlignment}" HourTickForeground="{DynamicResource SemiGrey6}" MinuteTickForeground="{DynamicResource SemiGrey4}" /> <u:ClockTicks
<Rectangle Width="8" Height="100" Fill="White" /> ShowHourTicks="{TemplateBinding ShowHourTicks}"
<Rectangle Width="4" /> ShowMinuteTicks="{TemplateBinding ShowMinuteTicks}"
<iri:PureCircle HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
Diameter="16" HourTickForeground="{DynamicResource SemiGrey6}"
Background="Red" /> MinuteTickForeground="{DynamicResource SemiGrey4}" />
<UniformGrid Rows="2" IsVisible="{TemplateBinding ShowHourHand}">
<Border
Width="16"
Margin="0,16,0,0"
VerticalAlignment="Stretch"
Background="{TemplateBinding HandBrush}"
CornerRadius="8" />
<UniformGrid.RenderTransform>
<RotateTransform Angle="{Binding HourAngle, RelativeSource={RelativeSource TemplatedParent}}" />
</UniformGrid.RenderTransform>
</UniformGrid>
<UniformGrid Rows="2" IsVisible="{TemplateBinding ShowMinuteHand}">
<Border
Width="8"
Margin="0,8,0,0"
VerticalAlignment="Stretch"
Background="{TemplateBinding HandBrush}"
CornerRadius="4" />
<UniformGrid.RenderTransform>
<RotateTransform Angle="{Binding MinuteAngle, RelativeSource={RelativeSource TemplatedParent}}" />
</UniformGrid.RenderTransform>
</UniformGrid>
<UniformGrid Rows="2" IsVisible="{TemplateBinding ShowSecondHand}">
<Border
Width="4"
Margin="0,4,0,0"
VerticalAlignment="Stretch"
Background="{TemplateBinding HandBrush}"
CornerRadius="4" />
<UniformGrid.RenderTransform>
<RotateTransform Angle="{Binding SecondAngle, RelativeSource={RelativeSource TemplatedParent}}" />
</UniformGrid.RenderTransform>
</UniformGrid>
<Ellipse
Width="20"
Height="20"
Fill="White"
Stroke="{DynamicResource SemiBlue5}"
StrokeThickness="3" />
</Grid> </Grid>
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>

View File

@@ -1,6 +1,8 @@
using Avalonia; using Avalonia;
using Avalonia.Controls.Metadata; using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Media;
namespace Ursa.Controls; namespace Ursa.Controls;
@@ -9,10 +11,10 @@ public class Clock: TemplatedControl
{ {
public const string PART_ClockTicks = "PART_ClockTicks"; public const string PART_ClockTicks = "PART_ClockTicks";
public static readonly StyledProperty<TimeSpan> TimeProperty = AvaloniaProperty.Register<Clock, TimeSpan>( public static readonly StyledProperty<DateTime> TimeProperty = AvaloniaProperty.Register<Clock, DateTime>(
nameof(Time)); nameof(Time), defaultBindingMode: BindingMode.TwoWay);
public TimeSpan Time public DateTime Time
{ {
get => GetValue(TimeProperty); get => GetValue(TimeProperty);
set => SetValue(TimeProperty, value); set => SetValue(TimeProperty, value);
@@ -36,22 +38,89 @@ public class Clock: TemplatedControl
set => SetValue(ShowMinuteTicksProperty, value); set => SetValue(ShowMinuteTicksProperty, value);
} }
public static readonly StyledProperty<double> HourHandMarginProperty = AvaloniaProperty.Register<Clock, double>( public static readonly StyledProperty<IBrush?> HandBrushProperty = AvaloniaProperty.Register<Clock, IBrush?>(
nameof(HourHandMargin)); nameof(HandBrush));
public double HourHandMargin public IBrush? HandBrush
{ {
get => GetValue(HourHandMarginProperty); get => GetValue(HandBrushProperty);
set => SetValue(HourHandMarginProperty, value); set => SetValue(HandBrushProperty, value);
}
public static readonly StyledProperty<bool> ShowHourHandProperty = AvaloniaProperty.Register<Clock, bool>(
nameof(ShowHourHand), defaultValue: true);
public bool ShowHourHand
{
get => GetValue(ShowHourHandProperty);
set => SetValue(ShowHourHandProperty, value);
}
public static readonly StyledProperty<bool> ShowMinuteHandProperty = AvaloniaProperty.Register<Clock, bool>(
nameof(ShowMinuteHand), defaultValue: true);
public bool ShowMinuteHand
{
get => GetValue(ShowMinuteHandProperty);
set => SetValue(ShowMinuteHandProperty, value);
}
public static readonly StyledProperty<bool> ShowSecondHandProperty = AvaloniaProperty.Register<Clock, bool>(
nameof(ShowSecondHand), defaultValue: true);
public bool ShowSecondHand
{
get => GetValue(ShowSecondHandProperty);
set => SetValue(ShowSecondHandProperty, value);
}
public static readonly DirectProperty<Clock, double> HourAngleProperty = AvaloniaProperty.RegisterDirect<Clock, double>(
nameof(HourAngle), o => o.HourAngle);
private double _hourAngle;
public double HourAngle
{
get => _hourAngle;
private set => SetAndRaise(HourAngleProperty, ref _hourAngle, value);
} }
public static readonly StyledProperty<double> MinuteHandMarginProperty = AvaloniaProperty.Register<Clock, double>( public static readonly DirectProperty<Clock, double> MinuteAngleProperty = AvaloniaProperty.RegisterDirect<Clock, double>(
nameof(MinuteHandMargin)); nameof(MinuteAngle), o => o.MinuteAngle);
private double _minuteAngle;
public double MinuteHandMargin public double MinuteAngle
{ {
get => GetValue(MinuteHandMarginProperty); get => _minuteAngle;
set => SetValue(MinuteHandMarginProperty, value); private set => SetAndRaise(MinuteAngleProperty, ref _minuteAngle, value);
}
public static readonly DirectProperty<Clock, double> SecondAngleProperty = AvaloniaProperty.RegisterDirect<Clock, double>(
nameof(SecondAngle), o => o.SecondAngle);
private double _secondAngle;
public double SecondAngle
{
get => _secondAngle;
private set => SetAndRaise(SecondAngleProperty, ref _secondAngle, value);
}
static Clock()
{
TimeProperty.Changed.AddClassHandler<Clock, DateTime>((clock, args)=>clock.OnTimeChanged(args));
}
private void OnTimeChanged(AvaloniaPropertyChangedEventArgs<DateTime> args)
{
DateTime time = args.NewValue.Value;
var hour = time.Hour;
var minute = time.Minute;
var second = time.Second;
var hourAngle = 360.0 / 12 * hour + 360.0 / 12 / 60 * minute;
var minuteAngle = 360.0 / 60 * minute + 360.0 / 60 / 60 * second;
var secondAngle = 360.0 / 60 * second;
HourAngle = hourAngle;
MinuteAngle = minuteAngle;
SecondAngle = secondAngle;
} }
protected override Size MeasureOverride(Size availableSize) protected override Size MeasureOverride(Size availableSize)