|
@@ -32,16 +32,20 @@ public class GaugeControl : Control
|
|
|
private FormattedText? _cachedValue;
|
|
private FormattedText? _cachedValue;
|
|
|
private string? _cachedValueText;
|
|
private string? _cachedValueText;
|
|
|
|
|
|
|
|
- protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { base.OnAttachedToVisualTree(e); ThemeHelper.ThemeChanged += OnThemeChanged; }
|
|
|
|
|
- protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) { ThemeHelper.ThemeChanged -= OnThemeChanged; base.OnDetachedFromVisualTree(e); }
|
|
|
|
|
|
|
+ protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { base.OnAttachedToVisualTree(e); ThemeHelper.ThemeChanged += OnThemeChanged; ConnectionStateHelper.StateChanged += OnConnectionStateChanged; }
|
|
|
|
|
+ protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) { ThemeHelper.ThemeChanged -= OnThemeChanged; ConnectionStateHelper.StateChanged -= OnConnectionStateChanged; base.OnDetachedFromVisualTree(e); }
|
|
|
private void OnThemeChanged()
|
|
private void OnThemeChanged()
|
|
|
{
|
|
{
|
|
|
- // 主题切换时清除 FormattedText 缓存(颜色变了)
|
|
|
|
|
_cachedTitle = null; _cachedTitleText = null;
|
|
_cachedTitle = null; _cachedTitleText = null;
|
|
|
_cachedUnit = null; _cachedUnitText = null;
|
|
_cachedUnit = null; _cachedUnitText = null;
|
|
|
_cachedValue = null; _cachedValueText = null;
|
|
_cachedValue = null; _cachedValueText = null;
|
|
|
InvalidateVisual();
|
|
InvalidateVisual();
|
|
|
}
|
|
}
|
|
|
|
|
+ private void OnConnectionStateChanged(bool connected)
|
|
|
|
|
+ {
|
|
|
|
|
+ _cachedValue = null; _cachedValueText = null;
|
|
|
|
|
+ InvalidateVisual();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
private static readonly Typeface s_typeface = new("Microsoft YaHei", FontStyle.Normal, FontWeight.Bold);
|
|
private static readonly Typeface s_typeface = new("Microsoft YaHei", FontStyle.Normal, FontWeight.Bold);
|
|
|
private static readonly Typeface s_typefaceNormal = new("Microsoft YaHei");
|
|
private static readonly Typeface s_typefaceNormal = new("Microsoft YaHei");
|
|
@@ -52,14 +56,31 @@ public class GaugeControl : Control
|
|
|
var bounds = new Rect(Bounds.Size);
|
|
var bounds = new Rect(Bounds.Size);
|
|
|
var cx = bounds.Width / 2; var cy = bounds.Height / 2 + 10;
|
|
var cx = bounds.Width / 2; var cy = bounds.Height / 2 + 10;
|
|
|
var radius = Math.Min(bounds.Width, bounds.Height) / 2 - 20;
|
|
var radius = Math.Min(bounds.Width, bounds.Height) / 2 - 20;
|
|
|
|
|
+ var disconnected = !ConnectionStateHelper.IsConnected;
|
|
|
|
|
|
|
|
context.DrawEllipse(ThemeHelper.PanelBg, null, new Rect(cx - radius - 5, cy - radius - 5, (radius + 5) * 2, (radius + 5) * 2));
|
|
context.DrawEllipse(ThemeHelper.PanelBg, null, new Rect(cx - radius - 5, cy - radius - 5, (radius + 5) * 2, (radius + 5) * 2));
|
|
|
- DrawArc(context, new Pen(ThemeHelper.Border, 8), cx, cy, radius, 135, 270);
|
|
|
|
|
|
|
+ DrawArc(context, new Pen(disconnected ? ConnectionStateHelper.DisconnectedGray : ThemeHelper.Border, 8), cx, cy, radius, 135, 270);
|
|
|
|
|
|
|
|
- var normalized = Math.Max(0, Math.Min(1, (Value - MinValue) / (MaxValue - MinValue)));
|
|
|
|
|
- var valueAngle = 135 + normalized * 270;
|
|
|
|
|
- var valueColor = ValueColor ?? ThemeHelper.Success;
|
|
|
|
|
- DrawArc(context, new Pen(valueColor, 8), cx, cy, radius, 135, valueAngle - 135);
|
|
|
|
|
|
|
+ var valueColor = disconnected ? ConnectionStateHelper.DisconnectedGray : (ValueColor ?? ThemeHelper.Success);
|
|
|
|
|
+ if (!disconnected)
|
|
|
|
|
+ {
|
|
|
|
|
+ var normalized = Math.Max(0, Math.Min(1, (Value - MinValue) / (MaxValue - MinValue)));
|
|
|
|
|
+ var valueAngle = 135 + normalized * 270;
|
|
|
|
|
+ DrawArc(context, new Pen(valueColor, 8), cx, cy, radius, 135, valueAngle - 135);
|
|
|
|
|
+
|
|
|
|
|
+ var pAngle = valueAngle * Math.PI / 180;
|
|
|
|
|
+ var pLen = radius * 0.7;
|
|
|
|
|
+ context.DrawLine(new Pen(valueColor, 3), new Point(cx, cy), new Point(cx + Math.Cos(pAngle) * pLen, cy + Math.Sin(pAngle) * pLen));
|
|
|
|
|
+ context.DrawEllipse(valueColor, null, new Rect(cx - 6, cy - 6, 12, 12));
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ // 断线:指针停在中间位置
|
|
|
|
|
+ var pAngle = 270 * Math.PI / 180;
|
|
|
|
|
+ var pLen = radius * 0.7;
|
|
|
|
|
+ context.DrawLine(new Pen(valueColor, 3), new Point(cx, cy), new Point(cx + Math.Cos(pAngle) * pLen, cy + Math.Sin(pAngle) * pLen));
|
|
|
|
|
+ context.DrawEllipse(valueColor, null, new Rect(cx - 6, cy - 6, 12, 12));
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
for (int i = 0; i <= 10; i++)
|
|
for (int i = 0; i <= 10; i++)
|
|
|
{
|
|
{
|
|
@@ -67,40 +88,44 @@ public class GaugeControl : Control
|
|
|
var rad = angle * Math.PI / 180;
|
|
var rad = angle * Math.PI / 180;
|
|
|
var isMajor = i % 5 == 0;
|
|
var isMajor = i % 5 == 0;
|
|
|
var tickLen = isMajor ? 12 : 6;
|
|
var tickLen = isMajor ? 12 : 6;
|
|
|
- context.DrawLine(new Pen(isMajor ? ThemeHelper.TextPrimary : ThemeHelper.TextDisabled, isMajor ? 2 : 1),
|
|
|
|
|
|
|
+ var tickColor = disconnected ? ConnectionStateHelper.DisconnectedGray : (isMajor ? ThemeHelper.TextPrimary : ThemeHelper.TextDisabled);
|
|
|
|
|
+ context.DrawLine(new Pen(tickColor, isMajor ? 2 : 1),
|
|
|
new Point(cx + Math.Cos(rad) * (radius - tickLen), cy + Math.Sin(rad) * (radius - tickLen)),
|
|
new Point(cx + Math.Cos(rad) * (radius - tickLen), cy + Math.Sin(rad) * (radius - tickLen)),
|
|
|
new Point(cx + Math.Cos(rad) * radius, cy + Math.Sin(rad) * radius));
|
|
new Point(cx + Math.Cos(rad) * radius, cy + Math.Sin(rad) * radius));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- var pAngle = valueAngle * Math.PI / 180;
|
|
|
|
|
- var pLen = radius * 0.7;
|
|
|
|
|
- context.DrawLine(new Pen(valueColor, 3), new Point(cx, cy), new Point(cx + Math.Cos(pAngle) * pLen, cy + Math.Sin(pAngle) * pLen));
|
|
|
|
|
- context.DrawEllipse(valueColor, null, new Rect(cx - 6, cy - 6, 12, 12));
|
|
|
|
|
-
|
|
|
|
|
- // Title(缓存:文字/字体不变时复用)
|
|
|
|
|
- if (_cachedTitle == null || _cachedTitleText != Title)
|
|
|
|
|
|
|
+ // Title
|
|
|
|
|
+ var titleColor = disconnected ? ConnectionStateHelper.DisconnectedText : ThemeHelper.TextPrimary;
|
|
|
|
|
+ if (_cachedTitle == null || _cachedTitleText != Title || disconnected)
|
|
|
{
|
|
{
|
|
|
- _cachedTitle = new FormattedText(Title, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, s_typeface, 12, ThemeHelper.TextPrimary);
|
|
|
|
|
|
|
+ _cachedTitle = new FormattedText(Title, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, s_typeface, 12, titleColor);
|
|
|
_cachedTitleText = Title;
|
|
_cachedTitleText = Title;
|
|
|
}
|
|
}
|
|
|
context.DrawText(_cachedTitle, new Point(cx - _cachedTitle.Width / 2, bounds.Y + 5));
|
|
context.DrawText(_cachedTitle, new Point(cx - _cachedTitle.Width / 2, bounds.Y + 5));
|
|
|
|
|
|
|
|
- // Value(缓存:格式化字符串不变时复用)
|
|
|
|
|
- var valStr = $"{Value:F1}";
|
|
|
|
|
|
|
+ // Value: 断线时显示 "---"
|
|
|
|
|
+ var valStr = disconnected ? "---" : $"{Value:F1}";
|
|
|
|
|
+ var valColor = disconnected ? ConnectionStateHelper.DisconnectedWarning : ThemeHelper.TextPrimary;
|
|
|
if (_cachedValue == null || _cachedValueText != valStr)
|
|
if (_cachedValue == null || _cachedValueText != valStr)
|
|
|
{
|
|
{
|
|
|
- _cachedValue = new FormattedText(valStr, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, s_typeface, 20, ThemeHelper.TextPrimary);
|
|
|
|
|
|
|
+ _cachedValue = new FormattedText(valStr, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, s_typeface, 20, valColor);
|
|
|
_cachedValueText = valStr;
|
|
_cachedValueText = valStr;
|
|
|
}
|
|
}
|
|
|
context.DrawText(_cachedValue, new Point(cx - _cachedValue.Width / 2, cy + radius * 0.3));
|
|
context.DrawText(_cachedValue, new Point(cx - _cachedValue.Width / 2, cy + radius * 0.3));
|
|
|
|
|
|
|
|
- // Unit(缓存:文字不变时复用)
|
|
|
|
|
|
|
+ // Unit
|
|
|
|
|
+ var unitColor = disconnected ? ConnectionStateHelper.DisconnectedGray : ThemeHelper.TextDisabled;
|
|
|
if (_cachedUnit == null || _cachedUnitText != Unit)
|
|
if (_cachedUnit == null || _cachedUnitText != Unit)
|
|
|
{
|
|
{
|
|
|
- _cachedUnit = new FormattedText(Unit, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, s_typefaceNormal, 10, ThemeHelper.TextDisabled);
|
|
|
|
|
|
|
+ _cachedUnit = new FormattedText(Unit, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, s_typefaceNormal, 10, unitColor);
|
|
|
_cachedUnitText = Unit;
|
|
_cachedUnitText = Unit;
|
|
|
}
|
|
}
|
|
|
context.DrawText(_cachedUnit, new Point(cx - _cachedUnit.Width / 2, cy + radius * 0.3 + _cachedValue.Height + 2));
|
|
context.DrawText(_cachedUnit, new Point(cx - _cachedUnit.Width / 2, cy + radius * 0.3 + _cachedValue.Height + 2));
|
|
|
|
|
+
|
|
|
|
|
+ if (disconnected)
|
|
|
|
|
+ {
|
|
|
|
|
+ context.DrawRectangle(ConnectionStateHelper.OverlayBrush, null, new Rect(cx - radius - 5, bounds.Y, (radius + 5) * 2, bounds.Height));
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private void DrawArc(DrawingContext context, IPen pen, double cx, double cy, double radius, double startAngle, double sweepAngle)
|
|
private void DrawArc(DrawingContext context, IPen pen, double cx, double cy, double radius, double startAngle, double sweepAngle)
|