WpfApp/src/components/SensorChart.xaml.cs
2025-10-11 15:36:43 +08:00

409 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace WpfApp.src.components;
/// <summary>
/// 刻度线数据结构
/// </summary>
public class ScaleLine
{
public double Y1 { get; set; }
public double Y2 { get; set; }
public double X1 { get; set; }
public double X2 { get; set; }
public double StrokeThickness { get; set; }
public string Label { get; set; }
public double LabelX { get; set; }
public double LabelY { get; set; }
public bool IsMainScale { get; set; }
}
/// <summary>
/// SensorChart.xaml 的交互逻辑
/// </summary>
public partial class SensorChart : UserControl, INotifyPropertyChanged
{
public SensorChart()
{
InitializeComponent();
DataContext = this;
// 设置默认值
SensorName = "传感器";
HeaderBackground = new SolidColorBrush(Color.FromRgb(230, 243, 255)); // #E6F3FF
Value = 0;
RedLineValues = new List<double>();
Level = SensorLevel.Medium; // 默认中等
// 生成初始刻度
GenerateScaleLines();
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#region
// 传感器名称
public static readonly DependencyProperty SensorNameProperty =
DependencyProperty.Register("SensorName", typeof(string), typeof(SensorChart),
new PropertyMetadata("传感器", OnSensorNameChanged));
public string SensorName
{
get { return (string)GetValue(SensorNameProperty); }
set { SetValue(SensorNameProperty, value); }
}
private static void OnSensorNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as SensorChart;
control?.OnPropertyChanged(nameof(SensorName));
}
// 标题背景色
public static readonly DependencyProperty HeaderBackgroundProperty =
DependencyProperty.Register("HeaderBackground", typeof(Brush), typeof(SensorChart),
new PropertyMetadata(new SolidColorBrush(Color.FromRgb(230, 243, 255)), OnHeaderBackgroundChanged));
public Brush HeaderBackground
{
get { return (Brush)GetValue(HeaderBackgroundProperty); }
set { SetValue(HeaderBackgroundProperty, value); }
}
private static void OnHeaderBackgroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as SensorChart;
control?.OnPropertyChanged(nameof(HeaderBackground));
}
// 数值
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(double), typeof(SensorChart),
new PropertyMetadata(0.0, OnValueChanged));
public double Value
{
get { return (double)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as SensorChart;
control?.UpdateBarPosition();
}
// 红线数值列表
public static readonly DependencyProperty RedLineValuesProperty =
DependencyProperty.Register("RedLineValues", typeof(List<double>), typeof(SensorChart),
new PropertyMetadata(new List<double>(), OnRedLineValuesChanged));
public List<double> RedLineValues
{
get { return (List<double>)GetValue(RedLineValuesProperty); }
set { SetValue(RedLineValuesProperty, value); }
}
private static void OnRedLineValuesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as SensorChart;
control?.UpdateRedLinePositions();
}
// 传感器等级
public static readonly DependencyProperty LevelProperty =
DependencyProperty.Register("Level", typeof(SensorLevel), typeof(SensorChart),
new PropertyMetadata(SensorLevel.Medium, OnLevelChanged));
public SensorLevel Level
{
get { return (SensorLevel)GetValue(LevelProperty); }
set { SetValue(LevelProperty, value); }
}
private static void OnLevelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as SensorChart;
control?.OnLevelChanged();
}
#endregion
#region
private double _barTop;
public double BarTop
{
get { return _barTop; }
private set
{
_barTop = value;
OnPropertyChanged(nameof(BarTop));
}
}
private double _barHeight;
public double BarHeight
{
get { return _barHeight; }
private set
{
_barHeight = value;
OnPropertyChanged(nameof(BarHeight));
}
}
private List<double> _redLinePositions = new List<double>();
public List<double> RedLinePositions
{
get { return _redLinePositions; }
private set
{
_redLinePositions = value;
OnPropertyChanged(nameof(RedLinePositions));
}
}
private List<ScaleLine> _scaleLines = new List<ScaleLine>();
public List<ScaleLine> ScaleLines
{
get { return _scaleLines; }
private set
{
_scaleLines = value;
OnPropertyChanged(nameof(ScaleLines));
}
}
// 当前等级的最小值
public double MinValue
{
get
{
switch (Level)
{
case SensorLevel.Low: return -20;
case SensorLevel.Medium: return -40;
case SensorLevel.High: return -60;
default: return -40;
}
}
}
// 当前等级的最大值
public double MaxValue
{
get
{
switch (Level)
{
case SensorLevel.Low: return 20;
case SensorLevel.Medium: return 40;
case SensorLevel.High: return 60;
default: return 40;
}
}
}
#endregion
#region
/// <summary>
/// 等级改变时的处理
/// </summary>
private void OnLevelChanged()
{
OnPropertyChanged(nameof(Level));
OnPropertyChanged(nameof(MinValue));
OnPropertyChanged(nameof(MaxValue));
GenerateScaleLines();
UpdateBarPosition();
UpdateRedLinePositions();
}
/// <summary>
/// 生成刻度线
/// </summary>
private void GenerateScaleLines()
{
var lines = new List<ScaleLine>();
double minVal = MinValue;
double maxVal = MaxValue;
// 根据等级确定刻度间隔
double mainInterval = (maxVal - minVal) / 8; // 8个主刻度间隔
double subInterval = mainInterval / 4; // 每个主刻度间隔4个小刻度
// 生成主刻度线
for (int i = 0; i <= 8; i++)
{
double value = maxVal - i * mainInterval;
double y = ValueToY(value);
lines.Add(new ScaleLine
{
X1 = 40,
Y1 = y,
X2 = 130,
Y2 = y,
StrokeThickness = 1,
Label = value.ToString("0"),
LabelX = 135,
LabelY = y - 5,
IsMainScale = true
});
// 生成小刻度线(除了最后一个主刻度)
if (i < 8)
{
for (int j = 1; j < 4; j++)
{
double subValue = value - j * subInterval;
double subY = ValueToY(subValue);
lines.Add(new ScaleLine
{
X1 = 40,
Y1 = subY,
X2 = 125,
Y2 = subY,
StrokeThickness = 0.5,
Label = "",
LabelX = 0,
LabelY = 0,
IsMainScale = false
});
}
}
}
ScaleLines = lines;
}
/// <summary>
/// 将数值转换为Y坐标位置
/// 根据当前等级动态计算刻度范围
/// </summary>
/// <param name="value">数值</param>
/// <returns>Y坐标</returns>
private double ValueToY(double value)
{
double minVal = MinValue;
double maxVal = MaxValue;
// 限制数值范围
value = Math.Max(minVal, Math.Min(maxVal, value));
// 线性映射maxVal对应Y=20minVal对应Y=420
double range = maxVal - minVal;
return 220 - ((value - minVal) / range - 0.5) * 400;
}
/// <summary>
/// 更新柱状图位置
/// </summary>
private void UpdateBarPosition()
{
if (Value >= 0)
{
// 正值从0线向上
BarTop = ValueToY(Value);
BarHeight = ValueToY(0) - ValueToY(Value);
}
else
{
// 负值从0线向下
BarTop = ValueToY(0);
BarHeight = ValueToY(Value) - ValueToY(0);
}
}
/// <summary>
/// 更新红线位置
/// </summary>
private void UpdateRedLinePositions()
{
var positions = new List<double>();
if (RedLineValues != null)
{
foreach (var value in RedLineValues)
{
positions.Add(ValueToY(value));
}
}
RedLinePositions = positions;
}
#endregion
#region
/// <summary>
/// 设置传感器数据
/// </summary>
/// <param name="name">传感器名称</param>
/// <param name="value">数值</param>
/// <param name="redLines">红线数值列表</param>
/// <param name="headerColor">标题背景色</param>
/// <param name="level">传感器等级</param>
public void SetSensorData(string name, double value, List<double> redLines = null, Color? headerColor = null, SensorLevel? level = null)
{
SensorName = name;
Value = value;
if (redLines != null)
{
RedLineValues = new List<double>(redLines);
}
if (headerColor.HasValue)
{
HeaderBackground = new SolidColorBrush(headerColor.Value);
}
if (level.HasValue)
{
Level = level.Value;
}
}
/// <summary>
/// 添加红线
/// </summary>
/// <param name="value">红线数值</param>
public void AddRedLine(double value)
{
var lines = new List<double>(RedLineValues) { value };
RedLineValues = lines;
}
/// <summary>
/// 清除所有红线
/// </summary>
public void ClearRedLines()
{
RedLineValues = new List<double>();
}
#endregion
}
/// <summary>
/// 传感器等级枚举
/// </summary>
public enum SensorLevel
{
Low, // 低等:-20到20
Medium, // 中等:-40到40
High // 高等:-60到60
}