using Avalonia; using Avalonia.Controls; using Avalonia.LogicalTree; using Avalonia.Markup.Xaml; using System; namespace ShakerApp.Views; public partial class TimeControl : UserControl { public TimeControl() { InitializeComponent(); } protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) { base.OnAttachedToLogicalTree(e); this.HourControl.ValueChanged += HourControl_ValueChanged; this.MinuteControl.ValueChanged += MinuteControl_ValueChanged; this.SecondControl.ValueChanged += SecondControl_ValueChanged; } private void SecondControl_ValueChanged(object? sender, NumericUpDownValueChangedEventArgs e) { if (changed) return; if(!this.SecondControl.Value.HasValue) { SecondControl.Value = 0; } float s = MathF.Floor(((float)(this.SecondControl.Value!)) / this.Increment) * Increment; s = Math.Clamp(s, 0, 60 - Increment); this.changed = true; this.SecondControl.Value = (decimal)s; this.SetValue(TimeProperty,(float)((float)this.HourControl.Value! * 3600 + (float)MinuteControl.Value! * 60 + s)); this.changed = false; } private void MinuteControl_ValueChanged(object? sender, NumericUpDownValueChangedEventArgs e) { if (changed) return; if(!this.MinuteControl.Value.HasValue) { this.MinuteControl.Value = 0; } byte m = (byte)MinuteControl.Value; m = Math.Clamp(m, (byte)0, (byte)59); this.changed = true; this.MinuteControl.Value = m; this.SetValue(TimeProperty, (float)((float)this.HourControl.Value! * 3600 + (float)MinuteControl.Value! * 60 + (float)this.SecondControl.Value!)); this.changed = false; } private void HourControl_ValueChanged(object? sender, NumericUpDownValueChangedEventArgs e) { if (changed) return; if (!this.HourControl.Value.HasValue) { this.HourControl.Value = 0; } uint m = (uint)HourControl.Value; this.changed = true; this.HourControl.Value = m; this.SetValue(TimeProperty, ((float)this.HourControl.Value! * 3600 + (float)MinuteControl.Value! * 60 + (float)this.SecondControl.Value!)); this.changed = false; } private bool changed = false; public static readonly StyledProperty TimeProperty = AvaloniaProperty.Register(nameof(Time), defaultBindingMode: Avalonia.Data.BindingMode.TwoWay, defaultValue: 0, coerce: static (obj, val) => { if (obj is TimeControl control) { float time = val; if (control.changed) return val; control.changed = true; uint hour = (uint)time / 3600; byte minute = (byte)((uint)time / 60 % 60); float second = MathF.Floor((time - (control.Hour * 3600 + control.Minute * 60)) / control.Increment) * control.Increment; control.HourControl.Value = hour; control.MinuteControl.Value = minute; control.SecondControl.Value = (decimal)second; control.changed = false; } return val; }); public float Time { get => GetValue(TimeProperty); set { var val = GetValue(TimeProperty); if (val == value) return; SetValue(TimeProperty, value); } } public static readonly StyledProperty HourProperty = AvaloniaProperty.Register(nameof(Hour), defaultValue: 0, coerce: (obj, val) => { if (obj is TimeControl control) { control.SetValue(TimeProperty, control.Hour * 3600 + control.Minute * 60 + control.Second); } return val; }); public uint Hour { get => GetValue(HourProperty); set { var val = GetValue(HourProperty); if (val == value) return; SetValue(HourProperty, value); } } public static readonly StyledProperty MinuteProperty = AvaloniaProperty.Register(nameof(Minute), defaultValue: 0, coerce:(obj,val)=> { byte temp = Math.Clamp(val, (byte)0, (byte)59); var control = (TimeControl)obj; control.SetValue(TimeProperty, control.Hour * 3600 + temp * 60 + control.Second); return temp; }); public byte Minute { get => GetValue(MinuteProperty); set { var val = GetValue(MinuteProperty); if (val == value) return; SetValue(MinuteProperty, value); } } public static readonly StyledProperty SecondProperty = AvaloniaProperty.Register(nameof(Second), defaultValue: 0, coerce: (obj, val) => { var control = (TimeControl)obj; float temp = Math.Clamp(val, 0f, 59f - control.Increment); control.SetValue(TimeProperty, control.Hour * 3600 + control.Minute * 60 + temp); return temp; }); public float Second { get => GetValue(SecondProperty); set { var val = GetValue(SecondProperty); if (val == value) return; SetValue(SecondProperty, value); } } public static readonly StyledProperty IncrementProperty = AvaloniaProperty.Register(nameof(Increment), defaultValue:0.01f ); public float Increment { get => GetValue(IncrementProperty); set => SetValue(IncrementProperty, value); } }