using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Collections.ObjectModel; using System.Data; using System.ComponentModel; using System.Drawing; using System.Windows.Forms.DataVisualization.Charting; namespace FLY.ControlLibrary { /// <summary> /// GraphScan.xaml 的交互逻辑 /// </summary> public partial class GraphScan : UserControl, INotifyPropertyChanged, IGraphBase2, IGraphBase { //设定数据统计范围 #region IGraphBase #region 附加属性 public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(GraphScan), 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(GraphScan), 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(GraphScan), 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(GraphScan), 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(GraphScan), 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(GraphScan), 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 ChartTypeProperty = DependencyProperty.Register("ChartType", typeof(System.Windows.Forms.DataVisualization.Charting.SeriesChartType), typeof(GraphScan), new PropertyMetadata( System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Column, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan).NotifyPropertyChanged("ChartType"); }))); public System.Windows.Forms.DataVisualization.Charting.SeriesChartType ChartType { get { return (System.Windows.Forms.DataVisualization.Charting.SeriesChartType)GetValue(ChartTypeProperty); } set { SetValue(ChartTypeProperty, value); } } /// <summary> /// 目标值 /// </summary> public static readonly DependencyProperty TargetProperty = DependencyProperty.Register("Target", typeof(int), typeof(GraphScan), new PropertyMetadata( 3000, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan).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(GraphScan), new PropertyMetadata( false, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan).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(GraphScan), new PropertyMetadata( false, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan).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(GraphScan), new PropertyMetadata( false, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan).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(GraphScan), new PropertyMetadata( false, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan).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(GraphScan), new PropertyMetadata( false, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan).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(GraphScan), new PropertyMetadata( 1000, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan).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(GraphScan), new PropertyMetadata( 3.0, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan).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(GraphScan), new PropertyMetadata( false, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan).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(GraphScan), new PropertyMetadata( 1000, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan).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(GraphScan), new PropertyMetadata( 0, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan).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(GraphScan), new PropertyMetadata( 0, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan).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(GraphScan), new PropertyMetadata( 49, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan).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(GraphScan), new PropertyMetadata( 0, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan).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(GraphScan), new PropertyMetadata( 49, new PropertyChangedCallback(delegate(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as GraphScan).NotifyPropertyChanged("DataLast"); }))); public int DataLast { get { return (int)GetValue(DataLastProperty); } set { SetValue(DataLastProperty, value); } } #endregion /// <summary> /// 数据源 /// </summary> private ObservableCollection<int> _datasource; public virtual ObservableCollection<int> 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; #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(GraphScan graph) { timer = new System.Windows.Threading.DispatcherTimer(); timer.Tick += new EventHandler(delegate(object sender, EventArgs e) { if (UpdateData) { UpdateData = false; graph.DataBindAll2(); } if (UpdateY) { UpdateY = false; graph.UpdateAxisY(); } if (UpdateX) { UpdateX = false; graph.UpdateXRange(); } if (UpdateCalX) { UpdateCalX = false; graph.UpdateDataCalRange(); graph.UpdateCalState(); } 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 GraphScan() { InitializeComponent(); InitializeComponent2(); //this.DataContext = this; grid_title.DataContext = this; //this.rectangle.DataContext = this; //this.run_title.DataContext = this; //this.run_title2.DataContext = this; //this.grid_left.DataContext = this; //this.grid_right.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 == "ChartType") { UpdateChartType(); } else if (e.PropertyName == "IsReversed") { chart1.ChartAreas[0].AxisX.IsReversed = IsReversed; } else if ((e.PropertyName == "HasCtrlLine") || (e.PropertyName == "CtrlLine")) { UpdateCtrlLine(); } } public virtual void UpdateChartType() { Series series1 = chart1.Series[0]; series1.ChartType = ChartType; if (ChartType == SeriesChartType.Line) { series1.MarkerStyle = System.Windows.Forms.DataVisualization.Charting.MarkerStyle.Circle; } else { series1.MarkerStyle = System.Windows.Forms.DataVisualization.Charting.MarkerStyle.None; } } public void SetDefault() { NotifyPropertyChanged("Target"); NotifyPropertyChanged("TAlarm"); NotifyPropertyChanged("YRangePercent"); NotifyPropertyChanged("ChartType"); NotifyPropertyChanged("FirstBoltNo"); NotifyPropertyChanged("FirstIndex"); NotifyPropertyChanged("LastIndex"); NotifyPropertyChanged("DataFirst"); NotifyPropertyChanged("DataLast"); AutoTarget = Target; } protected virtual void Test() { ObservableCollection<int> datasource = new ObservableCollection<int>(); // Populate series data Random random = new Random(); for (int i = 0; i < 40; i++) { datasource.Add(random.Next(3000) - 1500 + Target); } DataSource = datasource; } protected virtual void InitializeComponent2() { System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea(); System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend(); System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series(); // // chart1 // 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.Interval = 5; chartArea1.AxisX.IsLabelAutoFit = true; chartArea1.AxisX.LabelAutoFitStyle = LabelAutoFitStyles.DecreaseFont; 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))))); //this.chart1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(78)))), ((int)(((byte)(160)))), ((int)(((byte)(34))))); //chartArea1.BackColor = this.chart1.BackColor; //chartArea1.BackColor = System.Drawing.Color.Transparent; //chartArea1.BackColor = System.Drawing.Color.OldLace; //chartArea1.BackGradientStyle = System.Windows.Forms.DataVisualization.Charting.GradientStyle.TopBottom; //chartArea1.BackSecondaryColor = System.Drawing.Color.White; 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.Name = "Default"; //chartArea1.Position.Height = 100;// 42F; //chartArea1.Position.Width = 100;// 88F; //chartArea1.Position.X = 0;// 3F; //chartArea1.Position.Y = 0;// 10F; //chartArea1.ShadowColor = System.Drawing.Color.Transparent; this.chart1.ChartAreas.Add(chartArea1); //legend1.BackColor = System.Drawing.Color.Transparent; //legend1.Enabled = false; //legend1.Font = new System.Drawing.Font("Trebuchet MS", 8.25F, System.Drawing.FontStyle.Bold); //legend1.IsTextAutoFit = false; //legend1.Name = "Default"; //this.chart1.Legends.Add(legend1); //this.chart1.Location = new System.Drawing.Point(16, 32); this.chart1.Name = "chart1"; series1.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(180)))), ((int)(((byte)(26)))), ((int)(((byte)(59)))), ((int)(((byte)(105))))); series1.BorderWidth = 2; series1.ChartArea = chartArea1.Name; //TODO series1.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Column; series1.Color = System.Drawing.Color.FromArgb(((int)(((byte)(220)))), ((int)(((byte)(65)))), ((int)(((byte)(140)))), ((int)(((byte)(240))))); series1.MarkerSize = 6; //series1.MarkerStyle = System.Windows.Forms.DataVisualization.Charting.MarkerStyle.Circle; series1.Name = "Series 1"; series1.ShadowColor = System.Drawing.Color.Black; series1.ShadowOffset = 2; series1.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Int32; series1.YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double; this.chart1.Series.Add(series1); this.chart1.BackColor = System.Drawing.Color.Transparent; 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["Default"].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["Default"].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. chart1.ChartAreas["Default"].AxisX.Minimum = firstBoltNo + first; chart1.ChartAreas["Default"].AxisX.Maximum = firstBoltNo + last; } 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]); } } } /// <summary> /// 与 Multi,EmptyValue,DataFirst,DataLast 相关 /// </summary> public virtual void UpdateCalState() { int emptyvalue = EmptyValue; double multi = Multi; if (DataSource == null) { goto _err; } int datafirst = DataFirst; int datalast = DataLast; if (datafirst > datalast) { int swap = datalast; datalast = datafirst; datafirst = swap; } if (datafirst < 0) datafirst = 0; if (datalast >= DataSource.Count()) datalast = DataSource.Count() - 1; int datalen = datalast - datafirst + 1; if(datafirst>=DataSource.Count()) { goto _err; } if ((datafirst + datalen)>DataSource.Count()) { datalen = DataSource.Count() - datafirst; } List<int> datlist = DataSource.ToList().GetRange(datafirst,datalen); string title; var dats = from data in datlist where data!=emptyvalue select data; 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(); //chart1.ChartAreas["Default"].AxisX.Title = title; //chart1.ChartAreas["Default"].AxisX.TitleFont = new System.Drawing.Font("Times New Roman", 12, System.Drawing.FontStyle.Bold); //chart1.ChartAreas["Default"].AxisX.TitleForeColor = System.Drawing.Color.Black; } protected virtual void UpdateOnePoint(int index) { double multi = Multi; int emptyvalue = EmptyValue; DataPoint point; double v; if (DataSource[index] == emptyvalue) v = double.NaN; else v = DataSource[index] / multi; if (index >= chart1.Series[0].Points.Count) { chart1.Series[0].Points.AddXY( FirstBoltNo + index, v); point = chart1.Series["Series 1"].Points[index]; } else { point = chart1.Series["Series 1"].Points[index]; point.YValues[0] = v; point.XValue = FirstBoltNo + index; } //设定空数据 if (double.IsNaN(point.YValues[0])) { point.IsEmpty = true; System.Drawing.Color c = System.Drawing.Color.Transparent; point.MarkerColor = c; point.BorderColor = c; point.Color = c; } else { point.IsEmpty = false; System.Drawing.Color c; double alarm; double yrange; double target; bool ispercent; GetActualTargetAlarm(out target, out alarm, out yrange, out ispercent); double threshold1 = alarm * multi; double threshold2 = threshold1 * 2; target *= multi; if ((DataSource[index] > (target + threshold2)) || (DataSource[index] < (target - threshold2))) { c = System.Drawing.Color.Red; } else if ((DataSource[index] > (target + threshold1)) || (DataSource[index] < (target - threshold1))) { c = System.Drawing.Color.Orange; } else { c = System.Drawing.Color.Green; } if (ChartType == SeriesChartType.Line) { point.MarkerColor = c; point.BorderColor = chart1.Series["Series 1"].BorderColor; point.Color = chart1.Series["Series 1"].Color; } else { point.MarkerColor = c; point.BorderColor = c; point.Color = c; } } } void DataBindAll2() { double multi = Multi; int emptyvalue=EmptyValue; UpdateCalState(); chart1.Series["Series 1"].Points.Clear(); if (DataSource != null) { for (int i = 0; i < DataSource.Count(); i++) { chart1.Series["Series 1"].Points.AddXY( FirstBoltNo + i, (double)DataSource.ElementAt(i) / multi); UpdateOnePoint(i); } } CheckDataSourceEmpty(); } /// <summary> /// DataSource 里面的数据都是 EmptyValue 组成, 当修改数据时,应该clear ,再添加 /// </summary> private bool DataSourceIsEmpty = false; /// <summary> /// 当一个数据都没有时,需要添加空数据 /// </summary> public void CheckDataSourceEmpty() { if ((DataSource == null) || (DataSource.Count() == 0)) { chart1.Series["Series 1"].Points.Clear(); chart1.Series["Series 1"].Points.AddXY(FirstBoltNo, EmptyValue); chart1.Series["Series 1"].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) { if (ShowSettingDialogEvent != null) ShowSettingDialogEvent(this, new EventArgs()); } #region INotifyPropertyChanged 成员 public void NotifyPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public event PropertyChangedEventHandler PropertyChanged; #endregion } class IsValidConverter : IValueConverter { #region IValueConverter 成员 public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { bool isValid = (bool)value; if (isValid) return new SolidColorBrush(System.Windows.Media.Color.FromRgb(0x57, 0x9a, 0xab)); else return new SolidColorBrush(System.Windows.Media.Color.FromRgb(237, 106, 0)); } #endregion public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } } class LeftRightConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (values.Count() != 2) return null; if((!(values[0] is bool))||(!(values[1] is bool))) return null; bool leftright_isVisable = (bool)values[0]; bool leftright_IsReversed = (bool)values[1]; string flag = (string)parameter; if (!leftright_isVisable) return Visibility.Hidden; else { if (flag == "LIsL") { if (leftright_IsReversed) return Visibility.Hidden; else return Visibility.Visible; } else if (flag == "LIsR") { if (leftright_IsReversed) return Visibility.Visible; else return Visibility.Hidden; } else if (flag == "RIsL") { if (leftright_IsReversed) return Visibility.Visible; else return Visibility.Hidden; } else if (flag == "RIsR") { if (leftright_IsReversed) return Visibility.Hidden; else return Visibility.Visible; } } return null; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } } }