using Avalonia; using Avalonia.Controls; using Avalonia.Media; using System; using System.Globalization; namespace YZWater.Avalonia.Controls; public class WaterTankControl : Control { public static readonly StyledProperty WaterLevelProperty = AvaloniaProperty.Register(nameof(WaterLevel), 50.0); public static readonly StyledProperty TextProperty = AvaloniaProperty.Register(nameof(Text), string.Empty); public static readonly StyledProperty WaterColorProperty = AvaloniaProperty.Register(nameof(WaterColor)); public static readonly StyledProperty BorderColorProperty = AvaloniaProperty.Register(nameof(BorderColor)); public double WaterLevel { get => GetValue(WaterLevelProperty); set => SetValue(WaterLevelProperty, value); } public string Text { get => GetValue(TextProperty); set => SetValue(TextProperty, value); } public IBrush WaterColor { get => GetValue(WaterColorProperty); set => SetValue(WaterColorProperty, value); } public IBrush BorderColor { get => GetValue(BorderColorProperty); set => SetValue(BorderColorProperty, value); } static WaterTankControl() { AffectsRender(WaterLevelProperty, TextProperty, WaterColorProperty, BorderColorProperty); } protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { base.OnAttachedToVisualTree(e); ThemeHelper.ThemeChanged += OnThemeChanged; } protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) { ThemeHelper.ThemeChanged -= OnThemeChanged; base.OnDetachedFromVisualTree(e); } private void OnThemeChanged() => InvalidateVisual(); private static readonly Typeface s_typeface = new("Microsoft YaHei", FontStyle.Normal, FontWeight.Bold); public override void Render(DrawingContext context) { base.Render(context); var bounds = new Rect(Bounds.Size); var edgeWidth = 3.0; context.DrawRectangle(ThemeHelper.PanelBg, null, bounds); var borderColor = BorderColor ?? ThemeHelper.Border; context.DrawRectangle(null, new Pen(borderColor, edgeWidth), bounds); var waterHeight = (bounds.Height - edgeWidth * 2) * Math.Max(0, Math.Min(100, WaterLevel)) / 100.0; if (waterHeight > 0) { var waterColor = WaterColor ?? ThemeHelper.Success; var waterBrush = waterColor is SolidColorBrush sc ? new SolidColorBrush(sc.Color, 0.8) : waterColor; context.DrawRectangle(waterBrush, null, new Rect(bounds.X + edgeWidth, bounds.Y + bounds.Height - edgeWidth - waterHeight, bounds.Width - edgeWidth * 2, waterHeight)); } if (!string.IsNullOrEmpty(Text)) { var t = new FormattedText(Text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, s_typeface, 12, ThemeHelper.TextPrimary); context.DrawText(t, new Point(bounds.X + (bounds.Width - t.Width) / 2, bounds.Y + edgeWidth + 5)); } var lt = new FormattedText($"{WaterLevel:F1}%", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, s_typeface, 14, ThemeHelper.TextPrimary); var bg = new Rect(bounds.X + (bounds.Width - lt.Width - 10) / 2, bounds.Y + bounds.Height - edgeWidth - lt.Height - 10, lt.Width + 10, lt.Height + 6); context.DrawRectangle(new SolidColorBrush(Colors.Black, 0.5), null, bg); context.DrawText(lt, new Point(bg.X + 5, bg.Y + 3)); } protected override Size MeasureOverride(Size availableSize) => new Size(120, 160); }