| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374 |
- using Avalonia;
- using Avalonia.Controls;
- using Avalonia.Media;
- using Avalonia.Threading;
- using System;
- using System.Globalization;
- namespace YZWater.Avalonia.Controls;
- public class FanControl : Control
- {
- public static readonly StyledProperty<bool> IsRunningProperty =
- AvaloniaProperty.Register<FanControl, bool>(nameof(IsRunning), false);
- public static readonly StyledProperty<double> SpeedProperty =
- AvaloniaProperty.Register<FanControl, double>(nameof(Speed), 1.0);
- public static readonly StyledProperty<string> TextProperty =
- AvaloniaProperty.Register<FanControl, string>(nameof(Text), "风扇");
- public bool IsRunning { get => GetValue(IsRunningProperty); set => SetValue(IsRunningProperty, value); }
- public double Speed { get => GetValue(SpeedProperty); set => SetValue(SpeedProperty, value); }
- public string Text { get => GetValue(TextProperty); set => SetValue(TextProperty, value); }
- private double _angle;
- private IDisposable? _timer;
- static FanControl() { AffectsRender<FanControl>(IsRunningProperty, SpeedProperty, TextProperty); }
- protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { base.OnAttachedToVisualTree(e); if (IsRunning) StartAnim(); }
- protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) { base.OnDetachedFromVisualTree(e); StopAnim(); }
- protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
- {
- base.OnPropertyChanged(change);
- if (change.Property == IsRunningProperty) { if (IsRunning) StartAnim(); else { StopAnim(); _angle = 0; } }
- }
- private void StartAnim() { StopAnim(); _timer = DispatcherTimer.Run(() => { _angle += Speed * 2; if (_angle >= 360) _angle -= 360; InvalidateVisual(); return true; }, TimeSpan.FromMilliseconds(50)); }
- private void StopAnim() { _timer?.Dispose(); _timer = null; }
- public override void Render(DrawingContext context)
- {
- base.Render(context);
- var bounds = new Rect(Bounds.Size);
- var cx = bounds.Width / 2; var cy = bounds.Height / 2;
- var radius = Math.Min(bounds.Width, bounds.Height) / 2 - 5;
- var typeface = new Typeface("Microsoft YaHei", FontStyle.Normal, FontWeight.Bold);
- var fanColor = IsRunning ? ThemeHelper.Success() : ThemeHelper.TextDisabled();
- // 外框
- context.DrawRectangle(null, new Pen(ThemeHelper.Border(), 2), new Rect(cx - radius, cy - radius, radius * 2, radius * 2));
- // 叶片
- var bladeCount = 4;
- var bladeLen = radius * 0.8;
- var bladeW = radius * 0.25;
- for (int i = 0; i < bladeCount; i++)
- {
- var angle = _angle + (360.0 / bladeCount) * i;
- var bx = cx + Math.Cos(angle * Math.PI / 180) * bladeLen * 0.4;
- var by = cy + Math.Sin(angle * Math.PI / 180) * bladeLen * 0.4;
- context.DrawRectangle(fanColor, null, new Rect(bx - bladeW / 2, by - bladeLen / 2, bladeW, bladeLen));
- }
- // 中心
- var cr = radius * 0.15;
- context.DrawEllipse(fanColor, null, new Rect(cx - cr, cy - cr, cr * 2, cr * 2));
- // 文字
- if (!string.IsNullOrEmpty(Text))
- {
- var t = new FormattedText(Text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeface, 10, ThemeHelper.TextPrimary());
- context.DrawText(t, new Point(cx - t.Width / 2, bounds.Bottom - t.Height - 2));
- }
- }
- protected override Size MeasureOverride(Size availableSize) => new Size(50, 50);
- }
|