using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Drawing; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Forms.DataVisualization.Charting; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace FLY.ControlLibrary { /// <summary> /// GraphScan.xaml 的交互逻辑 /// </summary> public partial class GraphScan4 : UserControl, INotifyPropertyChanged { //设定数据统计范围 #region IGraphBase #region 附加属性 public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(GraphScan4), new PropertyMetadata("Title")); public string Title { get { return GetValue(TitleProperty) as string; } set { if (value != Title) { SetValue(TitleProperty, value); NotifyPropertyChanged("Title"); } } } public static readonly DependencyProperty Title2Property = DependencyProperty.Register("Title2", typeof(string), typeof(GraphScan4), new PropertyMetadata("")); public string Title2 { get { return GetValue(Title2Property) as string; } set { if (value != Title2) { SetValue(Title2Property, value); NotifyPropertyChanged("Title2"); } } } public static readonly DependencyProperty IsValidProperty = DependencyProperty.Register("IsValid", typeof(bool), typeof(GraphScan4), new PropertyMetadata(true)); public bool IsValid { get { return (bool)GetValue(IsValidProperty); } set { if (value != IsValid) { SetValue(IsValidProperty, value); NotifyPropertyChanged("IsValid"); } } } /// <summary> /// 计算结果 /// </summary> public static readonly DependencyProperty CalStateProperty = DependencyProperty.Register("CalState", typeof(string), typeof(GraphScan4), new PropertyMetadata( "Max:null Min:null Avg:null 2σ:null", new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e) { }))); public string CalState { get { return (string)GetValue(CalStateProperty); } set { SetValue(CalStateProperty, value); } } /// <summary> /// 空的数据,定义某个值为空,默认为 99999998 /// </summary> public static readonly DependencyProperty EmptyValueProperty = DependencyProperty.Register("EmptyValue", typeof(int), typeof(GraphScan4), new PropertyMetadata( 99999998, new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e) { }))); public int EmptyValue { get { return (int)GetValue(EmptyValueProperty); } set { SetValue(EmptyValueProperty, value); } } /// <summary> /// 放大倍数, 目标值= Target/放大倍数 /// </summary> public static readonly DependencyProperty MultiProperty = DependencyProperty.Register("Multi", typeof(int), typeof(GraphScan4), new PropertyMetadata( 100, new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e) { }))); public int Multi { get { return (int)GetValue(MultiProperty); } set { SetValue(MultiProperty, value); } } /// <summary> /// 目标值 /// </summary> public static readonly DependencyProperty TargetProperty = DependencyProperty.Register("Target", typeof(int), typeof(GraphScan4), new PropertyMetadata( 3000, new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan4).NotifyPropertyChanged("Target"); }))); public int Target { get { return (int)GetValue(TargetProperty); } set { SetValue(TargetProperty, value); } } private int autotarget; public int AutoTarget { get { return autotarget; } set { if (autotarget != value) { autotarget = value; NotifyPropertyChanged("AutoTarget"); } } } /// <summary> /// 自动目标值 /// </summary> public static readonly DependencyProperty IsAutoTargetProperty = DependencyProperty.Register("IsAutoTarget", typeof(bool), typeof(GraphScan4), new PropertyMetadata( false, new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan4).NotifyPropertyChanged("IsAutoTarget"); }))); public bool IsAutoTarget { get { return (bool)GetValue(IsAutoTargetProperty); } set { SetValue(IsAutoTargetProperty, value); } } /// <summary> /// 获取或设置指示是否将轴反转的标志 /// </summary> public static readonly DependencyProperty IsReversedProperty = DependencyProperty.Register("IsReversed", typeof(bool), typeof(GraphScan4), new PropertyMetadata( false, new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan4).NotifyPropertyChanged("IsReversed"); }))); public bool IsReversed { get { return (bool)GetValue(IsReversedProperty); } set { SetValue(IsReversedProperty, value); } } /// <summary> /// 获取或设置 左右标示是否反转 的标志 /// </summary> public static readonly DependencyProperty LeftRightIsReversedProperty = DependencyProperty.Register("LeftRightIsReversed", typeof(bool), typeof(GraphScan4), new PropertyMetadata( false, new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan4).NotifyPropertyChanged("LeftRightIsReversed"); }))); /// <summary> /// 左右标示 反转 /// </summary> public bool LeftRightIsReversed { get { return (bool)GetValue(LeftRightIsReversedProperty); } set { SetValue(LeftRightIsReversedProperty, value); } } /// <summary> /// 左右标示 可见 /// </summary> public static readonly DependencyProperty LeftRightIsVisableProperty = DependencyProperty.Register("LeftRightIsVisable", typeof(bool), typeof(GraphScan4), new PropertyMetadata( false, new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan4).NotifyPropertyChanged("LeftRightIsVisable"); }))); /// <summary> /// 左右标示 反转 /// </summary> public bool LeftRightIsVisable { get { return (bool)GetValue(LeftRightIsVisableProperty); } set { SetValue(LeftRightIsVisableProperty, value); } } /// <summary> /// %显示 /// </summary> public static readonly DependencyProperty IsPercentProperty = DependencyProperty.Register("IsPercent", typeof(bool), typeof(GraphScan4), new PropertyMetadata( false, new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan4).NotifyPropertyChanged("IsPercent"); }))); public bool IsPercent { get { return (bool)GetValue(IsPercentProperty); } set { SetValue(IsPercentProperty, value); } } /// <summary> /// 报警值 /// </summary> public static readonly DependencyProperty AlarmProperty = DependencyProperty.Register("Alarm", typeof(int), typeof(GraphScan4), new PropertyMetadata( 1000, new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan4).NotifyPropertyChanged("Alarm"); }))); public int Alarm { get { return (int)GetValue(AlarmProperty); } set { SetValue(AlarmProperty, value); } } /// <summary> /// Y轴是 Alarm 的N倍 默认3倍 /// </summary> public static readonly DependencyProperty YRangePercentProperty = DependencyProperty.Register("YRangePercent", typeof(double), typeof(GraphScan4), new PropertyMetadata( 3.0, new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan4).NotifyPropertyChanged("YRangePercent"); }))); public double YRangePercent { get { return (double)GetValue(YRangePercentProperty); } set { SetValue(YRangePercentProperty, value); } } /// <summary> /// 控制线 /// </summary> public static readonly DependencyProperty HasCtrlLineProperty = DependencyProperty.Register("HasCtrlLine", typeof(bool), typeof(GraphScan4), new PropertyMetadata( false, new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan4).NotifyPropertyChanged("HasCtrlLine"); }))); public bool HasCtrlLine { get { return (bool)GetValue(HasCtrlLineProperty); } set { SetValue(HasCtrlLineProperty, value); } } /// <summary> /// 控制线 /// </summary> public static readonly DependencyProperty CtrlLineProperty = DependencyProperty.Register("CtrlLine", typeof(int), typeof(GraphScan4), new PropertyMetadata( 1000, new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan4).NotifyPropertyChanged("CtrlLine"); }))); public int CtrlLine { get { return (int)GetValue(CtrlLineProperty); } set { SetValue(CtrlLineProperty, value); } } /// <summary> /// 第一个分区号 /// </summary> public static readonly DependencyProperty FirstBoltNoProperty = DependencyProperty.Register("FirstBoltNo", typeof(int), typeof(GraphScan4), new PropertyMetadata( 0, new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan4).NotifyPropertyChanged("FirstBoltNo"); }))); public int FirstBoltNo { get { return (int)GetValue(FirstBoltNoProperty); } set { SetValue(FirstBoltNoProperty, value); } } /// <summary> /// /// </summary> public static readonly DependencyProperty FirstIndexProperty = DependencyProperty.Register("FirstIndex", typeof(int), typeof(GraphScan4), new PropertyMetadata( 0, new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan4).NotifyPropertyChanged("FirstIndex"); }))); public int FirstIndex { get { return (int)GetValue(FirstIndexProperty); } set { SetValue(FirstIndexProperty, value); } } /// <summary> /// /// </summary> public static readonly DependencyProperty LastIndexProperty = DependencyProperty.Register("LastIndex", typeof(int), typeof(GraphScan4), new PropertyMetadata( 49, new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan4).NotifyPropertyChanged("LastIndex"); }))); public int LastIndex { get { return (int)GetValue(LastIndexProperty); } set { SetValue(LastIndexProperty, value); } } /// <summary> /// 数据统计的开始 /// </summary> public static readonly DependencyProperty DataFirstProperty = DependencyProperty.Register("DataFirst", typeof(int), typeof(GraphScan4), new PropertyMetadata( 0, new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan4).NotifyPropertyChanged("DataFirst"); }))); public int DataFirst { get { return (int)GetValue(DataFirstProperty); } set { SetValue(DataFirstProperty, value); } } /// <summary> /// 数据统计的结束 /// </summary> public static readonly DependencyProperty DataLastProperty = DependencyProperty.Register("DataLast", typeof(int), typeof(GraphScan4), new PropertyMetadata( 49, new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan4).NotifyPropertyChanged("DataLast"); }))); public int DataLast { get { return (int)GetValue(DataLastProperty); } set { SetValue(DataLastProperty, value); } } #endregion #region IGraphBase3 /// <summary> /// mm/分区 /// </summary> public static readonly DependencyProperty MmOfBoltProperty = DependencyProperty.Register("MmOfBolt", typeof(double), typeof(GraphScan4), new PropertyMetadata( 10.0, new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan4).NotifyPropertyChanged("MmOfBolt"); }))); /// <summary> /// mm/分区 /// </summary> public double MmOfBolt { get { return (double)GetValue(MmOfBoltProperty); } set { if (value != MmOfBolt) { SetValue(MmOfBoltProperty, value); NotifyPropertyChanged("MmOfBolt"); } } } /// <summary> /// X轴间隔 单位分区 /// </summary> public static readonly DependencyProperty XIntervalProperty = DependencyProperty.Register("XInterval", typeof(int), typeof(GraphScan4), new PropertyMetadata( 5, new PropertyChangedCallback(delegate (DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan4).NotifyPropertyChanged("XInterval"); }))); /// <summary> /// X轴间隔 单位分区 /// </summary> public int XInterval { get { return (int)GetValue(XIntervalProperty); } set { if (value != XInterval) { SetValue(XIntervalProperty, value); NotifyPropertyChanged("XInterval"); } } } #endregion /// <summary> /// 数据源 /// </summary> private ObservableCollection<GraphScan4Data> _datasource; /// <summary> /// 数据源 /// </summary> public virtual ObservableCollection<GraphScan4Data> DataSource { get { return _datasource; } set { if (_datasource != null) _datasource.CollectionChanged -= dataSource_CollectionChanged; _datasource = value; _datasource.CollectionChanged += dataSource_CollectionChanged; mRefresh.UpdateData = true; } } public event EventHandler ShowSettingDialogEvent; public event EventHandler TitleClickEvent; #endregion #region 刷新率控制 protected class Refresh { /// <summary> /// 控制刷新率 /// </summary> System.Windows.Threading.DispatcherTimer timer; bool updatedata_flag = false; bool updatey_flag = false; bool updatex_flag = false; bool updatecalx_flag = false; /// <summary> /// 最快0.1s 刷新一次 /// </summary> TimeSpan REFRESH_RATE = TimeSpan.FromSeconds(0.1); public Refresh(GraphScan4 graph) { timer = new System.Windows.Threading.DispatcherTimer(); timer.Tick += new EventHandler(delegate (object sender, EventArgs e) { if (UpdateData) { UpdateData = false; graph.DataBindAll_all(); } if (UpdateY) { UpdateY = false; graph.UpdateAxisY(); } if (UpdateX) { UpdateX = false; graph.UpdateXRange(); } if (UpdateCalX) { UpdateCalX = false; graph.UpdateDataCalRange(); graph.UpdateCalState_all(); } timer.Stop(); }); timer.Interval = REFRESH_RATE; timer.Start(); } public bool UpdateData { get { return updatedata_flag; } set { updatedata_flag = value; if (value) { if (!timer.IsEnabled) timer.Start(); } } } public bool UpdateY { get { return updatey_flag; } set { updatey_flag = value; if (value) { if (!timer.IsEnabled) timer.Start(); } } } public bool UpdateX { get { return updatex_flag; } set { updatex_flag = value; if (value) { if (!timer.IsEnabled) timer.Start(); } } } public bool UpdateCalX { get { return updatecalx_flag; } set { updatecalx_flag = value; if (value) { if (!timer.IsEnabled) timer.Start(); } } } } protected Refresh mRefresh; #endregion public GraphScan4() { InitializeComponent(); InitializeComponent2(); grid_title.DataContext = this; PropertyChanged += new PropertyChangedEventHandler(GraphScan_PropertyChanged); mRefresh = new Refresh(this); SetDefault(); //Test(); } void GraphScan_PropertyChanged(object sender, PropertyChangedEventArgs e) { //if (e.PropertyName == "AutoTarget") //{ // if (IsAutoTarget) // { // mRefresh.UpdateY = true; // mRefresh.UpdateData = true; // } //} if ((e.PropertyName == "Target") || (e.PropertyName == "Alarm") || (e.PropertyName == "YRangePercent") || (e.PropertyName == "IsAutoTarget") || (e.PropertyName == "IsPercent") || (e.PropertyName == "AutoTarget")) { mRefresh.UpdateY = true; mRefresh.UpdateData = true; } else if (e.PropertyName == "FirstBoltNo") { mRefresh.UpdateCalX = true; mRefresh.UpdateX = true; mRefresh.UpdateData = true; } else if (e.PropertyName == "FirstIndex" || e.PropertyName == "LastIndex") { mRefresh.UpdateX = true; } else if (e.PropertyName == "DataFirst" || e.PropertyName == "DataLast") { mRefresh.UpdateCalX = true; } else if (e.PropertyName == "IsReversed") { chart1.ChartAreas[0].AxisX.IsReversed = IsReversed; } else if ((e.PropertyName == "HasCtrlLine") || (e.PropertyName == "CtrlLine")) { UpdateCtrlLine(); } if (e.PropertyName == "MmOfBolt") { mRefresh.UpdateData = true; } else if (e.PropertyName == "XInterval") { mRefresh.UpdateX = true; } } public void SetDefault() { NotifyPropertyChanged("Target"); NotifyPropertyChanged("TAlarm"); NotifyPropertyChanged("YRangePercent"); NotifyPropertyChanged("ChartType"); NotifyPropertyChanged("FirstBoltNo"); NotifyPropertyChanged("FirstIndex"); NotifyPropertyChanged("LastIndex"); NotifyPropertyChanged("DataFirst"); NotifyPropertyChanged("DataLast"); AutoTarget = Target; } void InitializeComponent2() { System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea(); System.Windows.Forms.DataVisualization.Charting.Series series_sigma = new System.Windows.Forms.DataVisualization.Charting.Series(); System.Windows.Forms.DataVisualization.Charting.Series series_avg = new System.Windows.Forms.DataVisualization.Charting.Series(); chart1.Name = "chart1"; chart1.BackColor = System.Drawing.Color.Transparent; // // chart1 //--------------------------------------------------------------------------------------- chartArea1.Name = "chartArea1"; chartArea1.AxisX.LabelStyle.Font = new System.Drawing.Font("Trebuchet MS", 8.25F, System.Drawing.FontStyle.Bold); chartArea1.AxisX.LineColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); chartArea1.AxisX.MajorGrid.LineColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); chartArea1.AxisX.IsMarksNextToAxis = false; chartArea1.AxisX.IsLabelAutoFit = true; chartArea1.AxisX.LabelAutoFitStyle = LabelAutoFitStyles.DecreaseFont; chartArea1.AxisX.IntervalAutoMode = System.Windows.Forms.DataVisualization.Charting.IntervalAutoMode.VariableCount; chartArea1.AxisY.LabelStyle.Font = new System.Drawing.Font("Trebuchet MS", 8.25F, System.Drawing.FontStyle.Bold); chartArea1.AxisY.LineColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); chartArea1.AxisY.MajorGrid.LineColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); chartArea1.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); chartArea1.BorderDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Solid; //chartArea1.Position.Height = 100;// 42F; //chartArea1.Position.Width = 100;// 88F; //chartArea1.Position.X = 0;// 3F; //chartArea1.Position.Y = 0;// 10F; chart1.ChartAreas.Add(chartArea1); //--------------------------------------------------------------------------------------- series_sigma.Name = "series_sigma"; series_sigma.ChartArea = chartArea1.Name; series_sigma.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Range; series_sigma.Color = System.Drawing.Color.FromArgb(((int)(((byte)(220)))), ((int)(((byte)(65)))), ((int)(((byte)(140)))), ((int)(((byte)(240))))); series_sigma.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(180)))), ((int)(((byte)(26)))), ((int)(((byte)(59)))), ((int)(((byte)(105))))); series_sigma.BorderWidth = 2; //series_sigma.ShadowColor = System.Drawing.Color.Black; //series_sigma.ShadowOffset = 2; series_sigma.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Int32; series_sigma.YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double; chart1.Series.Add(series_sigma); //--------------------------------------------------------------------------------------- series_avg.Name = "series_avg"; series_avg.ChartArea = chartArea1.Name; series_avg.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Spline; series_avg.Color = System.Drawing.Color.FromArgb(((int)(((byte)(220)))), ((int)(((byte)(65)))), ((int)(((byte)(140)))), ((int)(((byte)(240))))); series_avg.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(180)))), ((int)(((byte)(26)))), ((int)(((byte)(59)))), ((int)(((byte)(105))))); series_avg.BorderWidth = 3; series_avg.ShadowColor = System.Drawing.Color.Black; series_avg.ShadowOffset = 2; series_avg.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Int32; series_avg.YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double; chart1.Series.Add(series_avg); //chart1.PrePaint += new EventHandler<ChartPaintEventArgs>(Chart1_PrePaint); this.chart1.PrePaint += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.ChartPaintEventArgs>(Chart1_PrePaint); } protected virtual void SetCustomLabel(Axis axisY, double p, GridTickTypes gt, System.Drawing.Color c, bool ispercent, string message) { double r = axisY.Maximum - axisY.Minimum; double f, t; f = p + r / 2; t = p - r / 2; double target = (axisY.Maximum + axisY.Minimum) / 2; CustomLabel customLabel; string str; if (!ispercent) { str = p.ToString("N1"); } else { //百分比模式!!!!!!! if (target == p) { str = p.ToString("N1"); } else { double percent; percent = ((p - target) / target) * 100; str = percent.ToString("N1") + "%"; } } if (!string.IsNullOrEmpty(message)) str = message + " " + str; customLabel = axisY.CustomLabels.Add(f, t, str); customLabel.GridTicks = gt; customLabel.ForeColor = c; } /// <summary> /// 获取实际应用的目标值,公差 /// </summary> /// <param name="target"></param> /// <param name="alarm"></param> /// <param name="yrange"></param> /// <param name="ispercent"></param> protected void GetActualTargetAlarm(out double target, out double alarm, out double yrange, out bool ispercent) { double multi = Multi; if (IsAutoTarget) target = AutoTarget / multi;//AutoTarget 计算得到的平均值 else target = Target / multi; ispercent = IsPercent; if ((ispercent) && (Target <= 0) || (Alarm < 0) || (target <= 0)) ispercent = false; if (ispercent) { alarm = target * Alarm / Target; } else { alarm = Alarm / multi; } yrange = alarm * YRangePercent; if ((alarm < 0.1) || (yrange < 0.3)) { alarm = 0.1; yrange = 0.3; } } /// <summary> /// 与 Multi,Target,YRange,Alarm 相关 /// </summary> public virtual void UpdateAxisY() { double alarm; double yrange; double target; bool ispercent; GetActualTargetAlarm(out target, out alarm, out yrange, out ispercent); Axis axisY = chart1.ChartAreas[0].AxisY; axisY.Crossing = target; // Set manual minimum and maximum values. axisY.Minimum = target - yrange; axisY.Maximum = target + yrange; axisY.CustomLabels.Clear(); //中间目标值,肯定不以%显示 SetCustomLabel(axisY, target, GridTickTypes.All, System.Drawing.Color.Green, false, null); //上下限 SetCustomLabel(axisY, target + alarm, GridTickTypes.All, System.Drawing.Color.DarkGoldenrod, ispercent, null); SetCustomLabel(axisY, target - alarm, GridTickTypes.All, System.Drawing.Color.DarkGoldenrod, ispercent, null); //2倍上下限 SetCustomLabel(axisY, target + alarm * 2, GridTickTypes.All, System.Drawing.Color.Red, ispercent, null); SetCustomLabel(axisY, target - alarm * 2, GridTickTypes.All, System.Drawing.Color.Red, ispercent, null); //显示范围数值 if ((yrange != alarm) && (yrange != 2 * alarm)) { SetCustomLabel(axisY, axisY.Minimum, GridTickTypes.TickMark, System.Drawing.Color.Black, ispercent, null); SetCustomLabel(axisY, axisY.Maximum, GridTickTypes.TickMark, System.Drawing.Color.Black, ispercent, null); } //显示范围太小,多加纵坐标 if (yrange <= alarm) { SetCustomLabel(axisY, target - yrange / 2, GridTickTypes.All, System.Drawing.Color.Black, ispercent, null); SetCustomLabel(axisY, target + yrange / 2, GridTickTypes.All, System.Drawing.Color.Black, ispercent, null); } } /// <summary> /// 与 FirstBoltNo,DataFirst,DataLast 相关 /// </summary> public virtual void UpdateDataCalRange() { int firstBoltNo = FirstBoltNo; int datafirst = DataFirst; int datalast = DataLast; if (datafirst > datalast) { int swap = datalast; datalast = datafirst; datafirst = swap; } System.Windows.Forms.DataVisualization.Charting.Axis axisX = chart1.ChartAreas[0].AxisX; axisX.CustomLabels.Clear(); System.Windows.Forms.DataVisualization.Charting.CustomLabel customlabel = new System.Windows.Forms.DataVisualization.Charting.CustomLabel( datafirst + firstBoltNo, datalast + firstBoltNo, CalState, 1, System.Windows.Forms.DataVisualization.Charting.LabelMarkStyle.LineSideMark); axisX.CustomLabels.Add(customlabel); } /// <summary> /// 与 FirstBoltNo,FirstIndex,LastIndex 相关 /// </summary> public virtual void UpdateXRange() { int firstBoltNo = FirstBoltNo; int first = FirstIndex; int last = LastIndex; if (first > last) { //交换 int swap = last; last = first; first = swap; } else if (first == last) { last = first + 10; } // Set manual minimum and maximum values. Axis axis = chart1.ChartAreas[0].AxisX; axis.Minimum = firstBoltNo + first; axis.Maximum = firstBoltNo + last; axis.Interval = XInterval; //0必须在 写着0mm axis.IntervalOffset = (0 - axis.Minimum) % XInterval; } public virtual void UpdateCtrlLine() { chart1.Invalidate(); } protected virtual void Chart1_PrePaint(object sender, System.Windows.Forms.DataVisualization.Charting.ChartPaintEventArgs e) { if (e.ChartElement is ChartArea) { ChartArea area = (ChartArea)e.ChartElement; //if (area.Name == "Default") { if (!HasCtrlLine) return; double c1 = ((double)(Target + CtrlLine)) / Multi; double c2 = ((double)(Target - CtrlLine)) / Multi; if (c1 > area.AxisY.Maximum || c2 < area.AxisY.Minimum) return; // Take Graphics object from chart Graphics graph = e.ChartGraphics.Graphics; // Convert X and Y values to screen position c1 = e.ChartGraphics.GetPositionFromAxis(area.Name, AxisName.Y, c1); c2 = e.ChartGraphics.GetPositionFromAxis(area.Name, AxisName.Y, c2); double XMin = e.ChartGraphics.GetPositionFromAxis(area.Name, AxisName.X, area.AxisX.Minimum); double XMax = e.ChartGraphics.GetPositionFromAxis(area.Name, AxisName.X, area.AxisX.Maximum); // Draw Maximum trangle System.Drawing.Pen darkPen = new System.Drawing.Pen(System.Drawing.Color.LightPink, 1); System.Drawing.PointF[] points = new System.Drawing.PointF[2]; points[0].X = (float)XMin; points[1].X = (float)XMax; points[0].Y = points[1].Y = (float)c1; // Convert relative coordinates to absolute coordinates. points[0] = e.ChartGraphics.GetAbsolutePoint(points[0]); points[1] = e.ChartGraphics.GetAbsolutePoint(points[1]); graph.DrawLine(darkPen, points[0], points[1]); points[0].X = (float)XMin; points[1].X = (float)XMax; points[0].Y = points[1].Y = (float)c2; // Convert relative coordinates to absolute coordinates. points[0] = e.ChartGraphics.GetAbsolutePoint(points[0]); points[1] = e.ChartGraphics.GetAbsolutePoint(points[1]); graph.DrawLine(darkPen, points[0], points[1]); } } } protected virtual void UpdateOnePoint_all(int index) { double multi = Multi; int emptyvalue = EmptyValue; DataPoint point_sigma; DataPoint point_avg; double avg; double upper; double lower; if ((DataSource[index].Avg == emptyvalue) || (DataSource[index].Sigma == emptyvalue)) { avg = double.NaN; upper = double.NaN; lower = double.NaN; } else { double sigma2 = 2 * DataSource[index].Sigma / multi; avg = DataSource[index].Avg / multi; upper = avg + sigma2; lower = avg - sigma2; } if (index >= chart1.Series["series_sigma"].Points.Count) { chart1.Series["series_sigma"].Points.AddXY( FirstBoltNo + index, upper, lower); point_sigma = chart1.Series["series_sigma"].Points[index]; chart1.Series["series_avg"].Points.AddXY( FirstBoltNo + index, avg); point_avg = chart1.Series["series_avg"].Points[index]; } else { point_sigma = chart1.Series["series_sigma"].Points[index]; point_sigma.YValues[0] = upper; point_sigma.YValues[1] = lower; point_sigma.XValue = FirstBoltNo + index; point_avg = chart1.Series["series_avg"].Points[index]; point_avg.YValues[0] = avg; point_avg.XValue = FirstBoltNo + index; } point_avg.AxisLabel = (point_avg.XValue * MmOfBolt).ToString("F0") + "mm"; //设定空数据 if (double.IsNaN(avg)) { point_sigma.IsEmpty = true; point_avg.IsEmpty = true; System.Drawing.Color c = System.Drawing.Color.Transparent; point_sigma.MarkerColor = c; point_sigma.BorderColor = c; point_sigma.Color = c; point_avg.MarkerColor = c; point_avg.BorderColor = c; point_avg.Color = c; } else { point_sigma.IsEmpty = false; point_avg.IsEmpty = false; double alarm; double target; double yrange; bool ispercent; GetActualTargetAlarm(out target, out alarm, out yrange, out ispercent); double threshold1 = alarm; double threshold2 = alarm * 2; System.Drawing.Color c; if (((upper) > (target + threshold2)) || ((upper) < (target - threshold2))) { c = System.Drawing.Color.Red; } else if (((lower) > (target + threshold2)) || ((lower) < (target - threshold2))) { c = System.Drawing.Color.Red; } else if (((upper) > (target + threshold1)) || ((upper) < (target - threshold1))) { c = System.Drawing.Color.Orange; } else if (((lower) > (target + threshold1)) || ((lower) < (target - threshold1))) { c = System.Drawing.Color.Orange; } else { c = System.Drawing.Color.Green; } point_sigma.BorderColor = c; point_sigma.Color = c; point_avg.Color = System.Drawing.Color.FromArgb(((int)(((byte)(220)))), ((int)(((byte)(65)))), ((int)(((byte)(140)))), ((int)(((byte)(240))))); point_avg.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(180)))), ((int)(((byte)(26)))), ((int)(((byte)(59)))), ((int)(((byte)(105))))); } } void DataBindAll_all() { chart1.Series["series_avg"].Points.Clear(); chart1.Series["series_sigma"].Points.Clear(); if (DataSource != null) { for (int i = 0; i < DataSource.Count(); i++) { UpdateOnePoint_all(i); } } CheckDataSourceEmpty(); UpdateCalState_all(); } /// <summary> /// 与 Multi,EmptyValue,DataFirst,DataLast 相关 /// </summary> public void UpdateCalState_all() { int emptyvalue = EmptyValue; double multi = Multi; if (DataSource == null) { goto _err; } string title; var dats_max = from data in DataSource where data.Avg != emptyvalue select data.Avg + data.Sigma * 2; var dats_min = from data in DataSource where data.Avg != emptyvalue select data.Avg - data.Sigma * 2; List<int> dats = new List<int>(); dats.AddRange(dats_max); dats.AddRange(dats_min); if (dats.Count() == 0) { goto _err; } else { //AutoTarget = (int)dats.Average(); double avg = dats.Average() / multi; double max = dats.Max() / multi; double min = dats.Min() / multi; double sum = 0; foreach (int dat in dats) { sum += Math.Pow(avg - (double)dat / multi, 2); } sum /= (dats.Count() - 1); double sigma = Math.Sqrt(sum); if (IsPercent) { title = "Max:+" + ((max / avg * 100) - 100).ToString("N1") + "% " + "Min:-" + (100 - (min / avg * 100)).ToString("N1") + "% " + "Avg:" + avg.ToString("N1") + " " + "2σ:" + (sigma / avg * 2 * 100).ToString("N1") + "%"; } else { title = "Max:" + max.ToString("N1") + " " + "Min:" + min.ToString("N1") + " " + "Avg:" + avg.ToString("N1") + " " + "2σ:" + (sigma * 2).ToString("N1"); } } goto _end; _err: //title = Properties.Resources.StrMax + ":" + "NULL " + // Properties.Resources.StrMin+":"+"NULL "+ // Properties.Resources.StrAvg+":"+"NULL "+ // "3Sigma:"+"NULL "; title = "Max:null Min:null Avg:null 2σ:null"; _end: CalState = title; UpdateDataCalRange(); } /// <summary> /// DataSource 里面的数据都是 EmptyValue 组成, 当修改数据时,应该clear ,再添加 /// </summary> private bool DataSourceIsEmpty = false; /// <summary> /// 当一个数据都没有时,需要添加空数据 /// </summary> public void CheckDataSourceEmpty() { if ((DataSource == null) || (DataSource.Count() == 0)) { chart1.Series["series_avg"].Points.Clear(); chart1.Series["series_avg"].Points.AddXY(FirstBoltNo, EmptyValue); chart1.Series["series_avg"].Points[0].IsEmpty = true; DataSourceIsEmpty = true; } else { DataSourceIsEmpty = false; } } void dataSource_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { mRefresh.UpdateData = true; } public void Button_Click(object sender, RoutedEventArgs e) { ShowSettingDialogEvent?.Invoke(this, new EventArgs()); } private void Button2_Click(object sender, RoutedEventArgs e) { TitleClickEvent?.Invoke(this, new EventArgs()); } #region INotifyPropertyChanged 成员 public void NotifyPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public event PropertyChangedEventHandler PropertyChanged; #endregion } public struct GraphScan4Data { public int Avg; public int Sigma; } }