diff --git a/demo/Ursa.Demo/Pages/ClockDemo.axaml b/demo/Ursa.Demo/Pages/ClockDemo.axaml
index 4dcde2d..892aa17 100644
--- a/demo/Ursa.Demo/Pages/ClockDemo.axaml
+++ b/demo/Ursa.Demo/Pages/ClockDemo.axaml
@@ -5,10 +5,14 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:u="https://irihi.tech/ursa"
+ xmlns:vm="clr-namespace:Ursa.Demo.ViewModels"
+ x:DataType="vm:ClockDemoViewModel"
+ x:CompileBindings="True"
d:DesignHeight="450"
d:DesignWidth="800"
+
mc:Ignorable="d">
-
+
diff --git a/demo/Ursa.Demo/ViewModels/ClockDemoViewModel.cs b/demo/Ursa.Demo/ViewModels/ClockDemoViewModel.cs
index 4670003..48cda91 100644
--- a/demo/Ursa.Demo/ViewModels/ClockDemoViewModel.cs
+++ b/demo/Ursa.Demo/ViewModels/ClockDemoViewModel.cs
@@ -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();
+ }
}
\ No newline at end of file
diff --git a/src/Ursa.Themes.Semi/Controls/Clock.axaml b/src/Ursa.Themes.Semi/Controls/Clock.axaml
index a62b9f9..14b554a 100644
--- a/src/Ursa.Themes.Semi/Controls/Clock.axaml
+++ b/src/Ursa.Themes.Semi/Controls/Clock.axaml
@@ -5,15 +5,55 @@
xmlns:u="https://irihi.tech/ursa">
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Ursa/Controls/Clock/Clock.cs b/src/Ursa/Controls/Clock/Clock.cs
index 92bb777..f73b0fd 100644
--- a/src/Ursa/Controls/Clock/Clock.cs
+++ b/src/Ursa/Controls/Clock/Clock.cs
@@ -1,6 +1,8 @@
using Avalonia;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
+using Avalonia.Data;
+using Avalonia.Media;
namespace Ursa.Controls;
@@ -9,10 +11,10 @@ public class Clock: TemplatedControl
{
public const string PART_ClockTicks = "PART_ClockTicks";
- public static readonly StyledProperty TimeProperty = AvaloniaProperty.Register(
- nameof(Time));
+ public static readonly StyledProperty TimeProperty = AvaloniaProperty.Register(
+ nameof(Time), defaultBindingMode: BindingMode.TwoWay);
- public TimeSpan Time
+ public DateTime Time
{
get => GetValue(TimeProperty);
set => SetValue(TimeProperty, value);
@@ -36,22 +38,89 @@ public class Clock: TemplatedControl
set => SetValue(ShowMinuteTicksProperty, value);
}
- public static readonly StyledProperty HourHandMarginProperty = AvaloniaProperty.Register(
- nameof(HourHandMargin));
+ public static readonly StyledProperty HandBrushProperty = AvaloniaProperty.Register(
+ nameof(HandBrush));
- public double HourHandMargin
+ public IBrush? HandBrush
{
- get => GetValue(HourHandMarginProperty);
- set => SetValue(HourHandMarginProperty, value);
+ get => GetValue(HandBrushProperty);
+ set => SetValue(HandBrushProperty, value);
+ }
+
+ public static readonly StyledProperty ShowHourHandProperty = AvaloniaProperty.Register(
+ nameof(ShowHourHand), defaultValue: true);
+
+ public bool ShowHourHand
+ {
+ get => GetValue(ShowHourHandProperty);
+ set => SetValue(ShowHourHandProperty, value);
+ }
+
+ public static readonly StyledProperty ShowMinuteHandProperty = AvaloniaProperty.Register(
+ nameof(ShowMinuteHand), defaultValue: true);
+
+ public bool ShowMinuteHand
+ {
+ get => GetValue(ShowMinuteHandProperty);
+ set => SetValue(ShowMinuteHandProperty, value);
+ }
+
+ public static readonly StyledProperty ShowSecondHandProperty = AvaloniaProperty.Register(
+ nameof(ShowSecondHand), defaultValue: true);
+
+ public bool ShowSecondHand
+ {
+ get => GetValue(ShowSecondHandProperty);
+ set => SetValue(ShowSecondHandProperty, value);
+ }
+
+
+
+ public static readonly DirectProperty HourAngleProperty = AvaloniaProperty.RegisterDirect(
+ nameof(HourAngle), o => o.HourAngle);
+ private double _hourAngle;
+ public double HourAngle
+ {
+ get => _hourAngle;
+ private set => SetAndRaise(HourAngleProperty, ref _hourAngle, value);
}
- public static readonly StyledProperty MinuteHandMarginProperty = AvaloniaProperty.Register(
- nameof(MinuteHandMargin));
-
- public double MinuteHandMargin
+ public static readonly DirectProperty MinuteAngleProperty = AvaloniaProperty.RegisterDirect(
+ nameof(MinuteAngle), o => o.MinuteAngle);
+ private double _minuteAngle;
+ public double MinuteAngle
{
- get => GetValue(MinuteHandMarginProperty);
- set => SetValue(MinuteHandMarginProperty, value);
+ get => _minuteAngle;
+ private set => SetAndRaise(MinuteAngleProperty, ref _minuteAngle, value);
+ }
+
+ public static readonly DirectProperty SecondAngleProperty = AvaloniaProperty.RegisterDirect(
+ 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, args)=>clock.OnTimeChanged(args));
+ }
+
+ private void OnTimeChanged(AvaloniaPropertyChangedEventArgs 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)