| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 | using System;using System.Collections.Generic;using System.ComponentModel;using System.Linq;using System.Text;using System.Threading.Tasks;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.Animation;using System.Windows.Media.Imaging;using System.Windows.Navigation;using System.Windows.Shapes;namespace FurnaceUI.Controls{    /// <summary>    /// FoupList.xaml 的交互逻辑    /// </summary>    public partial class FoupList : UserControl	{        public FoupList()        {            InitializeComponent();        }		/// <summary>		/// 使用动画的方式来更新值		/// </summary>		/// <param name="value">当前的数据值信息</param>		/// <param name="time">动画的时间,单位,毫秒</param>		public void SetValue(float value, double time = 300)		{			SingleAnimation animation = new SingleAnimation(value, TimeSpan.FromMilliseconds(time));			BeginAnimation(ValueProperty, animation);		}		// Using a DependencyProperty as the backing store for Value.  This enables animation, styling, binding, etc...		public static readonly DependencyProperty ValueProperty =			DependencyProperty.Register("Value", typeof(float), typeof(FoupList),				new PropertyMetadata(0f, new PropertyChangedCallback(RenderUpdateByPropertyChanged)));		/// <summary>		/// 获取或设置数值的当前值,应该处于最小值和最大值之间		/// </summary>		public float Value		{			get { return (float)GetValue(ValueProperty); }			set { SetValue(ValueProperty, value); }		}		/// <summary>		/// 获取或设置数值的起始值,默认为0		/// </summary>		public float ValueStart		{			get { return (float)GetValue(ValueStartProperty); }			set { SetValue(ValueStartProperty, value); }		}		// Using a DependencyProperty as the backing store for ValueStart.  This enables animation, styling, binding, etc...		public static readonly DependencyProperty ValueStartProperty =			DependencyProperty.Register("ValueStart", typeof(float), typeof(FoupList),				new PropertyMetadata(0f, new PropertyChangedCallback(RenderUpdateByPropertyChanged)));		/// <summary>		/// 获取或设置Wafer的分割段数,最小为2,最大1000,默认为10		/// </summary>		public int SegmentCount		{			get { return (int)GetValue(SegmentCountProperty); }			set { SetValue(SegmentCountProperty, value); }		}		// Using a DependencyProperty as the backing store for SegmentCount.  This enables animation, styling, binding, etc...		public static readonly DependencyProperty SegmentCountProperty =			DependencyProperty.Register("SegmentCount", typeof(int), typeof(FoupList),				new PropertyMetadata(25, new PropertyChangedCallback(RenderUpdateByPropertyChanged)));		/// <summary>		/// 获取或设置WaferList的颜色		/// </summary>		public Color FoupListColor		{			get { return (Color)GetValue(FoupListProperty); }			set { SetValue(FoupListProperty, value); }		}		// Using a DependencyProperty as the backing store for TemperatureColor.  This enables animation, styling, binding, etc...		public static readonly DependencyProperty FoupListProperty =			DependencyProperty.Register("FoupListColor", typeof(Color), typeof(FoupList),				new PropertyMetadata(Colors.Tomato, new PropertyChangedCallback(RenderUpdateByPropertyChanged)));		/// <summary>		/// 获取或设置WaferList的颜色		/// </summary>		public Color FoupListBackColor		{			get { return (Color)GetValue(FoupListBackColorProperty); }			set { SetValue(FoupListBackColorProperty, value); }		}		// Using a DependencyProperty as the backing store for TemperatureBackColor.  This enables animation, styling, binding, etc...		public static readonly DependencyProperty FoupListBackColorProperty =			DependencyProperty.Register("FoupListBackColor", typeof(Color), typeof(FoupList),				new PropertyMetadata(Colors.Silver, new PropertyChangedCallback(RenderUpdateByPropertyChanged)));		/// <summary>		/// 获取或设置是否显示WaferList的数值		/// </summary>		public bool IsRenderText		{			get { return (bool)GetValue(IsRenderTextProperty); }			set { SetValue(IsRenderTextProperty, value); }		}		// Using a DependencyProperty as the backing store for IsRenderText.  This enables animation, styling, binding, etc...		public static readonly DependencyProperty IsRenderTextProperty =			DependencyProperty.Register("IsRenderText", typeof(bool), typeof(FoupList),				new PropertyMetadata(false, new PropertyChangedCallback(RenderUpdateByPropertyChanged)));		/// <summary>		/// 获取或设置左侧的单位显示文本,默认是空		/// </summary>		public string LeftUnitText		{			get { return (string)GetValue(LeftUnitTextProperty); }			set { SetValue(LeftUnitTextProperty, value); }		}		// Using a DependencyProperty as the backing store for LeftUnitText.  This enables animation, styling, binding, etc...		public static readonly DependencyProperty LeftUnitTextProperty =			DependencyProperty.Register("LeftUnitText", typeof(string), typeof(FoupList),				new PropertyMetadata(" ", new PropertyChangedCallback(RenderUpdateByPropertyChanged)));		/// <summary>		/// 获取或设置右侧的单位显示文本,默认是空		/// </summary>		public string RightUnitText		{			get { return (string)GetValue(RightUnitTextProperty); }			set { SetValue(RightUnitTextProperty, value); }		}		// Using a DependencyProperty as the backing store for RightUnitText.  This enables animation, styling, binding, etc...		public static readonly DependencyProperty RightUnitTextProperty =			DependencyProperty.Register("RightUnitText", typeof(string), typeof(FoupList),				new PropertyMetadata(" ", new PropertyChangedCallback(RenderUpdateByPropertyChanged)));		/// <summary>		/// 获取或设置右侧轴的数值和左边的关系		/// </summary>		[Browsable(false)]		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]		public Func<float, float> RightDataTransfer { get; set; }		/// <summary>		/// 获取或设置数值的最大值,默认为100		/// </summary>		public float ValueMax		{			get { return (float)GetValue(ValueMaxProperty); }			set { SetValue(ValueMaxProperty, value); }		}		// Using a DependencyProperty as the backing store for ValueMax.  This enables animation, styling, binding, etc...		public static readonly DependencyProperty ValueMaxProperty =			DependencyProperty.Register("ValueMax", typeof(float), typeof(FoupList),				new PropertyMetadata(100f, new PropertyChangedCallback(RenderUpdateByPropertyChanged)));			/// <summary>		/// 当属性刷新的时候,进行强制更新绘图		/// </summary>		/// <param name="dependency"></param>		/// <param name="e"></param>		public static void RenderUpdateByPropertyChanged(DependencyObject dependency, DependencyPropertyChangedEventArgs e)		{			if (dependency is FoupList hslThermometer)			{				hslThermometer.FoupListUpdate();			}		}		/// <inheritdoc/>		protected override void OnRender(DrawingContext drawingContext)		{			base.OnRender(drawingContext);			FoupListUpdate();		}		private Color colorCenter = Colors.WhiteSmoke;		private Color colorBorder = Colors.Silver;		private SolidColorBrush SolidColorBrush = new SolidColorBrush();		/// <summary>		/// 刷新界面信息		/// </summary>		public void FoupListUpdate()		{			canvas1.Children.Clear();			int Width = (int)ActualWidth;			int Height = (int)ActualHeight;			if (Width < 20) return;			if (Height < 50) return;			float radius_mini = Height * 0.1f;			float radius_large = Height * 0.2f;			float top = radius_mini + 10;			float height_mid = Height - top - 10;			LinearGradientBrush linear = new LinearGradientBrush(				new GradientStopCollection(new List<GradientStop>()				{					new GradientStop(colorCenter, 0.0f),					new GradientStop(colorBorder, 0.3f),					new GradientStop(colorCenter, 0.8f),					new GradientStop(colorBorder, 1.0f)				}),				new Point(0, 0),				new Point(1, 0));			//WpfUtils.FillRectangle(canvas1, Width / 2.0f - radius_mini, top, radius_mini * 2, height_mid-10, FoupListBackColor);			//WpfUtils.DrawRectangle(canvas1, Width / 2.0f - radius_mini, top, radius_mini * 2, height_mid - 10, FoupListBackColor, 2);			double x = Width / 2.0f - radius_mini;			double y = top-4;			double width = radius_mini * 2;			double height = height_mid;			WpfUtils.DrawLine(canvas1, x, y,x+width,y, linear, 4);			WpfUtils.DrawLine(canvas1, x, y+height,x+width,y+height, linear, 4);			WpfUtils.DrawLine(canvas1, x+width/2.0f, y, x + width / 2.0f, y+height, linear, 8);			WpfUtils.DrawLine(canvas1, x+width-15, y, x + width-15, y+height, linear, 8);			// 绘制刻度线,以及刻度文本			for (int i = 0; i <= SegmentCount; i++)			{				float valueTmp = i * (ValueMax - ValueStart) / SegmentCount + ValueStart;				float paintTmp = height_mid - 10 - (valueTmp - ValueStart) / (ValueMax - ValueStart) * (height_mid - 10) + top;				double lineLength = width / 2.0f;				double startX = x + width / 4.0f;				if (i > 0)				{					for (int j = 1; j < 10; j++)					{						// 绘制细小的刻度						float segment_min = (height_mid - 10) / SegmentCount / 10 * j;						if (j == 5)						{							WpfUtils.DrawLine(canvas1, startX - lineLength * 0.12f, paintTmp + segment_min, startX+lineLength, paintTmp + segment_min, Foreground, 1);						}						else						{							WpfUtils.DrawLine(canvas1, startX, paintTmp + segment_min, startX+lineLength, paintTmp + segment_min, Foreground, 1);						}					}				}				//WpfUtils.DrawLine(canvas1, Width / 2.0f - radius_mini - Width * 0.14f, paintTmp, Width / 2.0f - radius_mini - 4, paintTmp, Foreground, 1);				// 左坐标轴				//WpfUtils.DrawLine(canvas1, Width / 2.0f - radius_mini - Width * 0.1f, paintTmp, Width / 2.0f - radius_mini - 4, paintTmp, Foreground, 1);								WpfUtils.DrawLine(canvas1, startX - lineLength * 0.2f, paintTmp, startX + lineLength, paintTmp, Foreground, 1);				WpfUtils.DrawString(canvas1, RightUnitText, Foreground, new System.Drawing.RectangleF(5, 0, Width - 10, top - radius_mini), HorizontalAlignment.Right, VerticalAlignment.Center);				//WpfUtils.DrawString(canvas1, valueTmp.ToString(), Foreground, new System.Drawing.RectangleF(-5f, paintTmp - 90, Width / 2.0f - radius_mini - Width * 0.13f, 100f), HorizontalAlignment.Right, VerticalAlignment.Bottom);				float stringX = (float)(x-40);				float stringY = paintTmp-20;				float stringWidth = 40;				float stringHeight = 40;				WpfUtils.DrawString(canvas1, valueTmp.ToString(), Foreground, new System.Drawing.RectangleF(stringX, stringY, stringWidth, stringHeight), HorizontalAlignment.Left, VerticalAlignment.Center);				WpfUtils.FillTriangle(canvas1,new Point(stringX+stringWidth*0.8, stringY+stringHeight*0.5),Colors.LightGreen,8,GraphDirection.Rightward);				WpfUtils.DrawString(canvas1, LeftUnitText, Foreground, new System.Drawing.RectangleF(5, 0, Width - 10, top - radius_mini), HorizontalAlignment.Left, VerticalAlignment.Center);			}			// 绘制温度计的背景			//WpfUtils.FillRectangle(canvas1, Width / 2.0f - radius_mini * 0.7f, top, radius_mini * 1.4f, height_mid - 10, linear);			if (IsRenderText)			{				WpfUtils.DrawString(canvas1, (170-Value+1).ToString(), Foreground, Width / 2.0f - radius_large, top + height_mid+20, radius_large * 2, radius_large * 2, HorizontalAlignment.Center, VerticalAlignment.Center);			}		}	}  }
 |