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 { /// /// FoupList.xaml 的交互逻辑 /// public partial class FoupList : UserControl { public FoupList() { InitializeComponent(); } /// /// 使用动画的方式来更新值 /// /// 当前的数据值信息 /// 动画的时间,单位,毫秒 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))); /// /// 获取或设置数值的当前值,应该处于最小值和最大值之间 /// public float Value { get { return (float)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } } /// /// 获取或设置数值的起始值,默认为0 /// 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))); /// /// 获取或设置Wafer的分割段数,最小为2,最大1000,默认为10 /// 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))); /// /// 获取或设置WaferList的颜色 /// 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))); /// /// 获取或设置WaferList的颜色 /// 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))); /// /// 获取或设置是否显示WaferList的数值 /// 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))); /// /// 获取或设置左侧的单位显示文本,默认是空 /// 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))); /// /// 获取或设置右侧的单位显示文本,默认是空 /// 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))); /// /// 获取或设置右侧轴的数值和左边的关系 /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public Func RightDataTransfer { get; set; } /// /// 获取或设置数值的最大值,默认为100 /// 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))); /// /// 当属性刷新的时候,进行强制更新绘图 /// /// /// public static void RenderUpdateByPropertyChanged(DependencyObject dependency, DependencyPropertyChangedEventArgs e) { if (dependency is FoupList hslThermometer) { hslThermometer.FoupListUpdate(); } } /// 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(); /// /// 刷新界面信息 /// 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() { 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); } } } }