(七十一)c#Winform自定義控制元件-折線圖
阿新 • • 發佈:2019-09-24
前提
入行已經7,8年了,一直想做一套漂亮點的自定義控制元件,於是就有了本系列文章。
GitHub:https://github.com/kwwwvagaa/NetWinformControl
碼雲:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
如果覺得寫的還行,請點個 star 支援一下吧
歡迎前來交流探討: 企鵝群568015492
麻煩部落格下方點個【推薦】,謝謝
NuGet
Install-Package HZH_Controls
目錄
https://www.cnblogs.com/bfyx/p/11364884.html
用處及效果
準備工作
請先了解GDI+相關知識
開始
新增一個類UCCurve 繼承自UserControl
新增一些控制屬性
1 /// <summary> 2 /// The value count maximum 3 /// </summary> 4 private const int value_count_max = 4096; 5 6 /// <summary> 7 /// The value maximum left 8 /// </summary> 9 private float value_max_left = 100f; 10 11 /// <summary> 12 /// The value minimum left 13 /// </summary> 14 private float value_min_left = 0f; 15 16 /// <summary> 17 /// The value maximum right 18 /// </summary> 19 private float value_max_right = 100f; 20 21 /// <summary> 22 /// The value minimum right 23 /// </summary> 24 private float value_min_right = 0f; 25 26 /// <summary> 27 /// The value segment 28 /// </summary> 29 private int value_Segment = 5; 30 31 /// <summary> 32 /// The value is abscissa strech 33 /// </summary> 34 private bool value_IsAbscissaStrech = false; 35 36 /// <summary> 37 /// The value strech data count maximum 38 /// </summary> 39 private int value_StrechDataCountMax = 300; 40 41 /// <summary> 42 /// The value is render dash line 43 /// </summary> 44 private bool value_IsRenderDashLine = true; 45 46 /// <summary> 47 /// The text format 48 /// </summary> 49 private string textFormat = "HH:mm"; 50 51 /// <summary> 52 /// The value interval abscissa text 53 /// </summary> 54 private int value_IntervalAbscissaText = 100; 55 56 /// <summary> 57 /// The random 58 /// </summary> 59 private Random random = null; 60 61 /// <summary> 62 /// The value title 63 /// </summary> 64 private string value_title = ""; 65 66 /// <summary> 67 /// The left right 68 /// </summary> 69 private int leftRight = 50; 70 71 /// <summary> 72 /// Up dowm 73 /// </summary> 74 private int upDowm = 50; 75 76 /// <summary> 77 /// The data list 78 /// </summary> 79 private Dictionary<string, CurveItem> data_list = null; 80 81 /// <summary> 82 /// The data text 83 /// </summary> 84 private string[] data_text = null; 85 86 /// <summary> 87 /// The auxiliary lines 88 /// </summary> 89 private List<AuxiliaryLine> auxiliary_lines; 90 91 /// <summary> 92 /// The auxiliary labels 93 /// </summary> 94 private List<AuxiliaryLable> auxiliary_Labels; 95 96 /// <summary> 97 /// The mark texts 98 /// </summary> 99 private List<MarkText> MarkTexts; 100 101 /// <summary> 102 /// The font size9 103 /// </summary> 104 private Font font_size9 = null; 105 106 /// <summary> 107 /// The font size12 108 /// </summary> 109 private Font font_size12 = null; 110 111 /// <summary> 112 /// The brush deep 113 /// </summary> 114 private Brush brush_deep = null; 115 116 /// <summary> 117 /// The pen normal 118 /// </summary> 119 private Pen pen_normal = null; 120 121 /// <summary> 122 /// The pen dash 123 /// </summary> 124 private Pen pen_dash = null; 125 126 /// <summary> 127 /// The color normal 128 /// </summary> 129 private Color color_normal = Color.DeepPink; 130 131 /// <summary> 132 /// The color deep 133 /// </summary> 134 private Color color_deep = Color.DimGray; 135 136 /// <summary> 137 /// The color dash 138 /// </summary> 139 private Color color_dash = Color.FromArgb(232, 232, 232); 140 141 /// <summary> 142 /// The color mark font 143 /// </summary> 144 private Color color_mark_font = Color.DodgerBlue; 145 146 /// <summary> 147 /// The brush mark font 148 /// </summary> 149 private Brush brush_mark_font = Brushes.DodgerBlue; 150 151 /// <summary> 152 /// The format left 153 /// </summary> 154 private StringFormat format_left = null; 155 156 /// <summary> 157 /// The format right 158 /// </summary> 159 private StringFormat format_right = null; 160 161 /// <summary> 162 /// The format center 163 /// </summary> 164 private StringFormat format_center = null; 165 166 /// <summary> 167 /// The is render right coordinate 168 /// </summary> 169 private bool isRenderRightCoordinate = true; 170 171 /// <summary> 172 /// The curve name width 173 /// </summary> 174 private int curveNameWidth = 100; 175 176 /// <summary> 177 /// The components 178 /// </summary> 179 private IContainer components = null; 180 181 /// <summary> 182 /// 獲取或設定控制元件的背景色。 183 /// </summary> 184 /// <value>The color of the back.</value> 185 /// <PermissionSet> 186 /// <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" /> 187 /// </PermissionSet> 188 [Browsable(true)] 189 [Description("獲取或設定控制元件的背景色")] 190 [Category("自定義")] 191 [DefaultValue(typeof(Color), "Transparent")] 192 [EditorBrowsable(EditorBrowsableState.Always)] 193 public override Color BackColor 194 { 195 get 196 { 197 return base.BackColor; 198 } 199 set 200 { 201 base.BackColor = value; 202 } 203 } 204 205 /// <summary> 206 /// Gets or sets the value maximum left. 207 /// </summary> 208 /// <value>The value maximum left.</value> 209 [Category("自定義")] 210 [Description("獲取或設定圖形的左縱座標的最大值,該值必須大於最小值")] 211 [Browsable(true)] 212 [DefaultValue(100f)] 213 public float ValueMaxLeft 214 { 215 get 216 { 217 return value_max_left; 218 } 219 set 220 { 221 value_max_left = value; 222 Invalidate(); 223 } 224 } 225 226 /// <summary> 227 /// Gets or sets the value minimum left. 228 /// </summary> 229 /// <value>The value minimum left.</value> 230 [Category("自定義")] 231 [Description("獲取或設定圖形的左縱座標的最小值,該值必須小於最大值")] 232 [Browsable(true)] 233 [DefaultValue(0f)] 234 public float ValueMinLeft 235 { 236 get 237 { 238 return value_min_left; 239 } 240 set 241 { 242 value_min_left = value; 243 Invalidate(); 244 } 245 } 246 247 /// <summary> 248 /// Gets or sets the value maximum right. 249 /// </summary> 250 /// <value>The value maximum right.</value> 251 [Category("自定義")] 252 [Description("獲取或設定圖形的右縱座標的最大值,該值必須大於最小值")] 253 [Browsable(true)] 254 [DefaultValue(100f)] 255 public float ValueMaxRight 256 { 257 get 258 { 259 return value_max_right; 260 } 261 set 262 { 263 value_max_right = value; 264 Invalidate(); 265 } 266 } 267 268 /// <summary> 269 /// Gets or sets the value minimum right. 270 /// </summary> 271 /// <value>The value minimum right.</value> 272 [Category("自定義")] 273 [Description("獲取或設定圖形的右縱座標的最小值,該值必須小於最大值")] 274 [Browsable(true)] 275 [DefaultValue(0f)] 276 public float ValueMinRight 277 { 278 get 279 { 280 return value_min_right; 281 } 282 set 283 { 284 value_min_right = value; 285 Invalidate(); 286 } 287 } 288 289 /// <summary> 290 /// Gets or sets the value segment. 291 /// </summary> 292 /// <value>The value segment.</value> 293 [Category("自定義")] 294 [Description("獲取或設定圖形的縱軸分段數")] 295 [Browsable(true)] 296 [DefaultValue(5)] 297 public int ValueSegment 298 { 299 get 300 { 301 return value_Segment; 302 } 303 set 304 { 305 value_Segment = value; 306 Invalidate(); 307 } 308 } 309 310 /// <summary> 311 /// Gets or sets a value indicating whether this instance is abscissa strech. 312 /// </summary> 313 /// <value><c>true</c> if this instance is abscissa strech; otherwise, <c>false</c>.</value> 314 [Category("自定義")] 315 [Description("獲取或設定所有的資料是否強制在一個介面裡顯示")] 316 [Browsable(true)] 317 [DefaultValue(false)] 318 public bool IsAbscissaStrech 319 { 320 get 321 { 322 return value_IsAbscissaStrech; 323 } 324 set 325 { 326 value_IsAbscissaStrech = value; 327 Invalidate(); 328 } 329 } 330 331 /// <summary> 332 /// Gets or sets the strech data count maximum. 333 /// </summary> 334 /// <value>The strech data count maximum.</value> 335 [Category("自定義")] 336 [Description("獲取或設定拉伸模式下的最大資料量")] 337 [Browsable(true)] 338 [DefaultValue(300)] 339 public int StrechDataCountMax 340 { 341 get 342 { 343 return value_StrechDataCountMax; 344 } 345 set 346 { 347 value_StrechDataCountMax = value; 348 Invalidate(); 349 } 350 } 351 352 /// <summary> 353 /// Gets or sets a value indicating whether this instance is render dash line. 354 /// </summary> 355 /// <value><c>true</c> if this instance is render dash line; otherwise, <c>false</c>.</value> 356 [Category("自定義")] 357 [Description("獲取或設定虛線是否進行顯示")] 358 [Browsable(true)] 359 [DefaultValue(true)] 360 public bool IsRenderDashLine 361 { 362 get 363 { 364 return value_IsRenderDashLine; 365 } 366 set 367 { 368 value_IsRenderDashLine = value; 369 Invalidate(); 370 } 371 } 372 373 /// <summary> 374 /// Gets or sets the color lines and text. 375 /// </summary> 376 /// <value>The color lines and text.</value> 377 [Category("自定義")] 378 [Description("獲取或設定座標軸及相關資訊文字的顏色")] 379 [Browsable(true)] 380 [DefaultValue(typeof(Color), "DimGray")] 381 public Color ColorLinesAndText 382 { 383 get 384 { 385 return color_deep; 386 } 387 set 388 { 389 color_deep = value; 390 InitializationColor(); 391 Invalidate(); 392 } 393 } 394 395 /// <summary> 396 /// Gets or sets the color dash lines. 397 /// </summary> 398 /// <value>The color dash lines.</value> 399 [Category("自定義")] 400 [Description("獲取或設定虛線的顏色")] 401 [Browsable(true)] 402 public Color ColorDashLines 403 { 404 get 405 { 406 return color_dash; 407 } 408 set 409 { 410 color_dash = value; 411 if (pen_dash != null) 412 pen_dash.Dispose(); 413 pen_dash = new Pen(color_dash); 414 pen_dash.DashStyle = DashStyle.Custom; 415 pen_dash.DashPattern = new float[2] 416 { 417 5f, 418 5f 419 }; 420 Invalidate(); 421 } 422 } 423 424 /// <summary> 425 /// Gets or sets the interval abscissa text. 426 /// </summary> 427 /// <value>The interval abscissa text.</value> 428 [Category("自定義")] 429 [Description("獲取或設定縱向虛線的分隔情況,單位為多少個數據")] 430 [Browsable(true)] 431 [DefaultValue(100)] 432 public int IntervalAbscissaText 433 { 434 get 435 { 436 return value_IntervalAbscissaText; 437 } 438 set 439 { 440 value_IntervalAbscissaText = value; 441 Invalidate(); 442 } 443 } 444 445 /// <summary> 446 /// Gets or sets the text add format. 447 /// </summary> 448 /// <value>The text add format.</value> 449 [Category("自定義")] 450 [Description("獲取或設定實時資料新增時文字相對應於時間的格式化字串,預設HH:mm")] 451 [Browsable(true)] 452 [DefaultValue("HH:mm")] 453 public string TextAddFormat 454 { 455 get 456 { 457 return textFormat; 458 } 459 set 460 { 461 textFormat = value; 462 Invalidate(); 463 } 464 } 465 466 /// <summary> 467 /// Gets or sets the title. 468 /// </summary> 469 /// <value>The title.</value> 470 [Category("自定義")] 471 [Description("獲取或設定圖示的標題資訊")] 472 [Browsable(true)] 473 [DefaultValue("")] 474 public string Title 475 { 476 get 477 { 478 return value_title; 479 } 480 set 481 { 482 value_title = value; 483 Invalidate(); 484 } 485 } 486 487 /// <summary> 488 /// Gets or sets a value indicating whether this instance is render right coordinate. 489 /// </summary> 490 /// <value><c>true</c> if this instance is render right coordinate; otherwise, <c>false</c>.</value> 491 [Category("自定義")] 492 [Description("獲取或設定是否顯示右側的座標系資訊")] 493 [Browsable(true)] 494 [DefaultValue(true)] 495 public bool IsRenderRightCoordinate 496 { 497 get 498 { 499 return isRenderRightCoordinate; 500 } 501 set 502 { 503 isRenderRightCoordinate = value; 504 Invalidate(); 505 } 506 } 507 508 /// <summary> 509 /// Gets or sets the width of the curve name. 510 /// </summary> 511 /// <value>The width of the curve name.</value> 512 [Browsable(true)] 513 [Description("獲取或設定曲線名稱的佈局寬度")] 514 [Category("自定義")] 515 [DefaultValue(100)] 516 public int CurveNameWidth 517 { 518 get 519 { 520 return curveNameWidth; 521 } 522 set 523 { 524 if (value > 10) 525 { 526 curveNameWidth = value; 527 } 528 } 529 }
建構函式做一些初始化
1 public UCCurve() 2 { 3 InitializeComponent(); 4 random = new Random(); 5 data_list = new Dictionary<string, CurveItem>(); 6 auxiliary_lines = new List<AuxiliaryLine>(); 7 MarkTexts = new List<MarkText>(); 8 auxiliary_Labels = new List<AuxiliaryLable>(); 9 format_left = new StringFormat 10 { 11 LineAlignment = StringAlignment.Center, 12 Alignment = StringAlignment.Near 13 }; 14 format_right = new StringFormat 15 { 16 LineAlignment = StringAlignment.Center, 17 Alignment = StringAlignment.Far 18 }; 19 format_center = new StringFormat 20 { 21 LineAlignment = StringAlignment.Center, 22 Alignment = StringAlignment.Center 23 }; 24 font_size9 = new Font("微軟雅黑", 9f); 25 font_size12 = new Font("微軟雅黑", 12f); 26 InitializationColor(); 27 pen_dash = new Pen(color_deep); 28 pen_dash.DashStyle = DashStyle.Custom; 29 pen_dash.DashPattern = new float[2] 30 { 31 5f, 32 5f 33 }; 34 SetStyle(ControlStyles.UserPaint | ControlStyles.SupportsTransparentBackColor, true); 35 SetStyle(ControlStyles.ResizeRedraw, true); 36 SetStyle(ControlStyles.OptimizedDoubleBuffer, true); 37 SetStyle(ControlStyles.AllPaintingInWmPaint, true); 38 }
重繪
1 protected override void OnPaint(PaintEventArgs e) 2 { 3 try 4 { 5 Graphics graphics = e.Graphics; 6 graphics.SetGDIHigh(); 7 if (BackColor != Color.Transparent) 8 { 9 graphics.Clear(BackColor); 10 } 11 int width = base.Width; 12 int height = base.Height; 13 if (width < 120 || height < 60) 14 { 15 return; 16 } 17 Point[] array = new Point[4] 18 { 19 new Point(leftRight - 1, upDowm - 8), 20 new Point(leftRight - 1, height - upDowm), 21 new Point(width - leftRight, height - upDowm), 22 new Point(width - leftRight, upDowm - 8) 23 }; 24 graphics.DrawLine(pen_normal, array[0], array[1]); 25 graphics.DrawLine(pen_normal, array[1], array[2]); 26 if (isRenderRightCoordinate) 27 { 28 graphics.DrawLine(pen_normal, array[2], array[3]); 29 } 30 31 if (!string.IsNullOrEmpty(value_title)) 32 { 33 graphics.DrawString(value_title, font_size9, brush_deep, new Rectangle(0, 0, width - 1, 20), format_center); 34 } 35 36 if (data_list.Count > 0) 37 { 38 float num = leftRight + 10; 39 foreach (KeyValuePair<string, CurveItem> item in data_list) 40 { 41 if (item.Value.Visible) 42 { 43 var titleSize=graphics.MeasureString(item.Key, Font); 44 SolidBrush solidBrush = item.Value.LineRenderVisiable ? new SolidBrush(item.Value.LineColor) : new SolidBrush(Color.FromArgb(80, item.Value.LineColor)); 45 graphics.FillRectangle(solidBrush, num + 8f, 24f, 20f, 14f); 46 graphics.DrawString(item.Key, Font, solidBrush, new PointF(num + 30f, 24f+(14 - titleSize.Height) / 2)); 47 item.Value.TitleRegion = new RectangleF(num, 24f, 60f, 18f); 48 solidBrush.Dispose(); 49 num += titleSize.Width + 30; 50 } 51 } 52 } 53 54 55 for (int i = 0; i < auxiliary_Labels.Count; i++) 56 { 57 if (!string.IsNullOrEmpty(auxiliary_Labels[i].Text)) 58 { 59 int num2 = (auxiliary_Labels[i].LocationX > 1f) ? ((int)auxiliary_Labels[i].LocationX) : ((int)(auxiliary_Labels[i].LocationX * (float)width)); 60 int num3 = (int)graphics.MeasureString(auxiliary_Labels[i].Text, Font).Width + 3; 61 Point[] points = new Point[6] 62 { 63 new Point(num2, 11), 64 new Point(num2 + 10, 20), 65 new Point(num2 + num3 + 10, 20), 66 new Point(num2 + num3 + 10, 0), 67 new Point(num2 + 10, 0), 68 new Point(num2, 11) 69 }; 70 graphics.FillPolygon(auxiliary_Labels[i].TextBack, points); 71 graphics.DrawString(auxiliary_Labels[i].Text, Font, auxiliary_Labels[i].TextBrush, new Rectangle(num2 + 7, 0, num3 + 3, 20), format_center); 72 } 73 } 74 ControlHelper.PaintTriangle(graphics, brush_deep, new Point(leftRight - 1, upDowm - 8), 4, GraphDirection.Upward); 75 if (isRenderRightCoordinate) 76 { 77 ControlHelper.PaintTriangle(graphics, brush_deep, new Point(width - leftRight, upDowm - 8), 4, GraphDirection.Upward); 78 } 79 for (int j = 0; j < auxiliary_lines.Count; j++) 80 { 81 if (auxiliary_lines[j].IsLeftFrame) 82 { 83 auxiliary_lines[j].PaintValue = ControlHelper.ComputePaintLocationY(value_max_left, value_min_left, height - upDowm - upDowm, auxiliary_lines[j].Value) + (float)upDowm; 84 } 85 else 86 { 87 auxiliary_lines[j].PaintValue = ControlHelper.ComputePaintLocationY(value_max_right, value_min_right, height - upDowm - upDowm, auxiliary_lines[j].Value) + (float)upDowm; 88 } 89 } 90 for (int k = 0; k <= value_Segment; k++) 91 { 92 float value = (float)((double)k * (double)(value_max_left - value_min_left) / (double)value_Segment + (double)value_min_left); 93 float num4 = ControlHelper.ComputePaintLocationY(value_max_left, value_min_left, height - upDowm - upDowm, value) + (float)upDowm; 94 if (IsNeedPaintDash(num4)) 95 { 96 graphics.DrawLine(pen_normal, leftRight - 4, num4, leftRight - 1, num4); 97 RectangleF layoutRectangle = new RectangleF(0f, num4 - 9f, leftRight - 4, 20f); 98 graphics.DrawString(value.ToString(), font_size9, brush_deep, layoutRectangle, format_right); 99 if (isRenderRightCoordinate) 100 { 101 float num5 = (float)k * (value_max_right - value_min_right) / (float)value_Segment + value_min_right; 102 graphics.DrawLine(pen_normal, width - leftRight + 1, num4, width - leftRight + 4, num4); 103 layoutRectangle.Location = new PointF(width - leftRight + 4, num4 - 9f); 104 graphics.DrawString(num5.ToString(), font_size9, brush_deep, layoutRectangle, format_left); 105 } 106 if (k > 0 && value_IsRenderDashLine) 107 { 108 graphics.DrawLine(pen_dash, leftRight, num4, width - leftRight, num4); 109 } 110 } 111 } 112 if (value_IsRenderDashLine) 113 { 114 if (value_IsAbscissaStrech) 115 { 116 float num6 = (float)(width - leftRight * 2) * 1f / (float)(value_StrechDataCountMax - 1); 117 int num7 = CalculateDataCountByOffect(num6); 118 for (int l = 0; l < value_StrechDataCountMax; l += num7) 119 { 120 if (l > 0 && l < value_StrechDataCountMax - 1) 121 { 122 graphics.DrawLine(pen_dash, (float)l * num6 + (float)leftRight, upDowm, (float)l * num6 + (float)leftRight, height - upDowm - 1); 123 } 124 if (data_text != null && l < data_text.Length && (float)l * num6 + (float)leftRight < (float)(data_text.Length - 1) * num6 + (float)leftRight - 40f) 125 { 126 graphics.DrawString(layoutRectangle: new Rectangle((int)((float)l * num6), height - upDowm + 1, leftRight * 2, upDowm), s: data_text[l], font: font_size9, brush: brush_deep, format: format_center); 127 } 128 } 129 string[] array2 = data_text; 130 if (array2 != null && array2.Length > 1) 131 { 132 if (data_text.Length < value_StrechDataCountMax) 133 { 134 graphics.DrawLine(pen_dash, (float)(data_text.Length - 1) * num6 + (float)leftRight, upDowm, (float)(data_text.Length - 1) * num6 + (float)leftRight, height - upDowm - 1); 135 } 136 graphics.DrawString(layoutRectangle: new Rectangle((int)((float)(data_text.Length - 1) * num6 + (float)leftRight) - leftRight, height - upDowm + 1, leftRight * 2, upDowm), s: data_text[data_text.Length - 1], font: font_size9, brush: brush_deep, format: format_center); 137 } 138 } 139 else if (value_IntervalAbscissaText > 0) 140 { 141 int num8 = width - 2 * leftRight + 1; 142 for (int m = leftRight; m < width - leftRight; m += value_IntervalAbscissaText) 143 { 144 if (m != leftRight) 145 { 146 graphics.DrawLine(pen_dash, m, upDowm, m, height - upDowm - 1); 147 } 148 if (data_text == null) 149 { 150 continue; 151 } 152 int num9 = (num8 > data_text.Length) ? data_text.Length : num8; 153 if (m - leftRight < data_text.Length && num9 - (m - leftRight) > 40) 154 { 155 if (data_text.Length <= num8) 156 { 157 graphics.DrawString(layoutRectangle: new Rectangle(m - leftRight, height - upDowm + 1, leftRight * 2, upDowm), s: data_text[m - leftRight], font: font_size9, brush: brush_deep, format: format_center); 158 } 159 else 160 { 161 graphics.DrawString(layoutRectangle: new Rectangle(m - leftRight, height - upDowm + 1, leftRight * 2, upDowm), s: data_text[m - leftRight + data_text.Length - num8], font: font_size9, brush: brush_deep, format: format_center); 162 } 163 } 164 } 165 string[] array3 = data_text; 166 if (array3 != null && array3.Length > 1) 167 { 168 if (data_text.Length >= num8) 169 { 170 graphics.DrawString(layoutRectangle: new Rectangle(width - leftRight - leftRight, height - upDowm + 1, leftRight * 2, upDowm), s: data_text[data_text.Length - 1], font: font_size9, brush: brush_deep, format: format_center); 171 } 172 else 173 { 174 graphics.DrawLine(pen_dash, data_text.Length + leftRight - 1, upDowm, data_text.Length + leftRight - 1, height - upDowm - 1); 175 graphics.DrawString(layoutRectangle: new Rectangle(data_text.Length + leftRight - 1 - leftRight, height - upDowm + 1, leftRight * 2, upDowm), s: data_text[data_text.Length - 1], font: font_size9, brush: brush_deep, format: format_center); 176 } 177 } 178 } 179 } 180 for (int n = 0; n < auxiliary_lines.Count; n++) 181 { 182 if (auxiliary_lines[n].IsLeftFrame) 183 { 184 graphics.DrawLine(auxiliary_lines[n].GetPen(), leftRight - 4, auxiliary_lines[n].PaintValue, leftRight - 1, auxiliary_lines[n].PaintValue); 185 graphics.DrawString(layoutRectangle: new RectangleF(0f, auxiliary_lines[n].PaintValue - 9f, leftRight - 4, 20f), s: auxiliary_lines[n].Value.ToString(), font: font_size9, brush: auxiliary_lines[n].LineTextBrush, format: format_right); 186 } 187 else 188 { 189 graphics.DrawLine(auxiliary_lines[n].GetPen(), width - leftRight + 1, auxiliary_lines[n].PaintValue, width - leftRight + 4, auxiliary_lines[n].PaintValue); 190 graphics.DrawString(layoutRectangle: new RectangleF(width - leftRight + 4, auxiliary_lines[n].PaintValue - 9f, leftRight - 4, 20f), s: auxiliary_lines[n].Value.ToString(), font: font_size9, brush: auxiliary_lines[n].LineTextBrush, format: format_left); 191 } 192 graphics.DrawLine(auxiliary_lines[n].GetPen(), leftRight, auxiliary_lines[n].PaintValue, width - leftRight, auxiliary_lines[n].PaintValue); 193 } 194 if (value_IsAbscissaStrech) 195 { 196 foreach (MarkText MarkText in MarkTexts) 197 { 198 foreach (KeyValuePair<string, CurveItem> item2 in data_list) 199 { 200 if (item2.Value.Visible && item2.Value.LineRenderVisiable && !(item2.Key != MarkText.CurveKey)) 201 { 202 float[] data = item2.Value.Data; 203 if (data != null && data.Length > 1) 204 { 205 float num10 = (float)(width - leftRight * 2) * 1f / (float)(value_StrechDataCountMax - 1); 206 if (MarkText.Index >= 0 && MarkText.Index < item2.Value.Data.Length) 207 { 208 PointF pointF = new PointF((float)leftRight + (float)MarkText.Index * num10, ControlHelper.ComputePaintLocationY(item2.Value.IsLeftFrame ? value_max_left : value_max_right, item2.Value.IsLeftFrame ? value_min_left : value_min_right, height - upDowm - upDowm, item2.Value.Data[MarkText.Index]) + (float)upDowm); 209 graphics.FillEllipse(new SolidBrush(MarkText.TextColor ?? item2.Value.LineColor), new RectangleF(pointF.X - 3f, pointF.Y - 3f, 6f, 6f)); 210 switch ((MarkText.PositionStyle == MarkTextPositionStyle.Auto) ? MarkText.CalculateDirectionFromDataIndex(item2.Value.Data, MarkText.Index) : MarkText.PositionStyle) 211 { 212 case MarkTextPositionStyle.Left: 213 graphics.DrawString(MarkText.Text, Font, new SolidBrush(MarkText.TextColor ?? item2.Value.LineColor), new RectangleF(pointF.X - 100f, pointF.Y - (float)Font.Height, 100 - MarkText.MarkTextOffect, Font.Height * 2), format_right); 214 break; 215 case MarkTextPositionStyle.Up: 216 graphics.DrawString(MarkText.Text, Font, new SolidBrush(MarkText.TextColor ?? item2.Value.LineColor), new RectangleF(pointF.X - 100f, pointF.Y - (float)Font.Height - (float)MarkText.MarkTextOffect, 200f, Font.Height + 2), format_center); 217 break; 218 case MarkTextPositionStyle.Right: 219 graphics.DrawString(MarkText.Text, Font, new SolidBrush(MarkText.TextColor ?? item2.Value.LineColor), new RectangleF(pointF.X + (float)MarkText.MarkTextOffect, pointF.Y - (float)Font.Height, 100f, Font.Height * 2), format_left); 220 break; 221 case MarkTextPositionStyle.Down: 222 graphics.DrawString(MarkText.Text, Font, new SolidBrush(MarkText.TextColor ?? item2.Value.LineColor), new RectangleF(pointF.X - 100f, pointF.Y + (float)MarkText.MarkTextOffect, 200f, Font.Height + 2), format_center); 223 break; 224 } 225 } 226 } 227 } 228 } 229 } 230 foreach (CurveItem value2 in data_list.Values) 231 { 232 if (value2.Visible && value2.LineRenderVisiable) 233 { 234 float[] data2 = value2.Data; 235 if (data2 != null && data2.Length > 1) 236 { 237 float num11 = (float)(width - leftRight * 2) * 1f / (float)(value_StrechDataCountMax - 1); 238 PointF[] array4 = new PointF[value2.Data.Length]; 239 for (int num12 = 0; num12 < value2.Data.Length; num12++) 240 { 241 array4[num12].X = (float)leftRight + (float)num12 * num11; 242 array4[num12].Y = ControlHelper.ComputePaintLocationY(value2.IsLeftFrame ? value_max_left : value_max_right, value2.IsLeftFrame ? value_min_left : value_min_right, height - upDowm - upDowm, value2.Data[num12]) + (float)upDowm; 243 if (!string.IsNullOrEmpty(value2.MarkText[num12])) 244 { 245 using (Brush brush = new SolidBrush(value2.LineColor)) 246 { 247 graphics.FillEllipse(brush, new RectangleF(array4[num12].X - 3f, array4[num12].Y - 3f, 6f, 6f)); 248 switch (MarkText.CalculateDirectionFromDataIndex(value2.Data, num12)) 249 { 250 case MarkTextPositionStyle.Left: 251 graphics.DrawString(value2.MarkText[num12], Font, brush, new RectangleF(array4[num12].X - 100f, array4[num12].Y - (float)Font.Height, 100 - MarkText.MarkTextOffect, Font.Height * 2), format_right); 252 break; 253 case MarkTextPositionStyle.Up: 254 graphics.DrawString(value2.MarkText[num12], Font, brush, new RectangleF(array4[num12].X - 100f, array4[num12].Y - (float)Font.Height - (float)MarkText.MarkTextOffect, 200f, Font.Height + 2), format_center); 255 break; 256 case MarkTextPositionStyle.Right: 257 graphics.DrawString(value2.MarkText[num12], Font, brush, new RectangleF(array4[num12].X + (float)MarkText.MarkTextOffect, array4[num12].Y - (float)Font.Height, 100f, Font.Height * 2), format_left); 258 break; 259 case MarkTextPositionStyle.Down: 260 graphics.DrawString(value2.MarkText[num12], Font, brush, new RectangleF(array4[num12].X - 100f, array4[num12].Y + (float)MarkText.MarkTextOffect, 200f, Font.Height + 2), format_center); 261 break; 262 } 263 } 264 } 265 } 266 using (Pen pen2 = new Pen(value2.LineColor, value2.LineThickness)) 267 { 268 if (value2.IsSmoothCurve) 269 { 270 graphics.DrawCurve(pen2, array4); 271 } 272 else 273 { 274 graphics.DrawLines(pen2, array4); 275 } 276 } 277 } 278 } 279 } 280 } 281 else 282 { 283 foreach (MarkText MarkText2 in MarkTexts) 284 { 285 foreach (KeyValuePair<string, CurveItem> item3 in data_list) 286 { 287 if (item3.Value.Visible && item3.Value.LineRenderVisiable && !(item3.Key != MarkText2.CurveKey)) 288 { 289 float[] data3 = item3.Value.Data; 290 if (data3 != null && data3.Length > 1 && MarkText2.Index >= 0 && MarkText2.Index < item3.Value.Data.Length) 291 { 292 PointF pointF2 = new PointF(leftRight + MarkText2.Index, ControlHelper.ComputePaintLocationY(item3.Value.IsLeftFrame ? value_max_left : value_max_right, item3.Value.IsLeftFrame ? value_min_left : value_min_right, height - upDowm - upDowm, item3.Value.Data[MarkText2.Index]) + (float)upDowm); 293 graphics.FillEllipse(new SolidBrush(MarkText2.TextColor ?? item3.Value.LineColor), new RectangleF(pointF2.X - 3f, pointF2.Y - 3f, 6f, 6f)); 294 switch ((MarkText2.PositionStyle == MarkTextPositionStyle.Auto) ? MarkText.CalculateDirectionFromDataIndex(item3.Value.Data, MarkText2.Index) : MarkText2.PositionStyle) 295 { 296 case MarkTextPositionStyle.Left: 297 graphics.DrawString(MarkText2.Text, Font, new SolidBrush(MarkText2.TextColor ?? item3.Value.LineColor), new RectangleF(pointF2.X - 100f, pointF2.Y - (float)Font.Height, 100 - MarkText.MarkTextOffect, Font.Height * 2), format_right); 298 break; 299 case MarkTextPositionStyle.Up: 300 graphics.DrawString(MarkText2.Text, Font, new SolidBrush(MarkText2.TextColor ?? item3.Value.LineColor), new RectangleF(pointF2.X - 100f, pointF2.Y - (float)Font.Height - (float)MarkText.MarkTextOffect, 200f, Font.Height + 2), format_center); 301 break; 302 case MarkTextPositionStyle.Right: 303 graphics.DrawString(MarkText2.Text, Font, new SolidBrush(MarkText2.TextColor ?? item3.Value.LineColor), new RectangleF(pointF2.X + (float)MarkText.MarkTextOffect, pointF2.Y - (float)Font.Height, 100f, Font.Height * 2), format_left); 304 break; 305 case MarkTextPositionStyle.Down: 306 graphics.DrawString(MarkText2.Text, Font, new SolidBrush(MarkText2.TextColor ?? item3.Value.LineColor), new RectangleF(pointF2.X - 100f, pointF2.Y + (float)MarkText.MarkTextOffect, 200f, Font.Height + 2), format_center); 307 break; 308 } 309 } 310 } 311 } 312 } 313 foreach (CurveItem value3 in data_list.Values) 314 { 315 if (value3.Visible && value3.LineRenderVisiable) 316 { 317 float[] data4 = value3.Data; 318 if (data4 != null && data4.Length > 1) 319 { 320 int num13 = width - 2 * leftRight + 1; 321 PointF[] array5; 322 if (value3.Data.Length <= num13) 323 { 324 array5 = new PointF[value3.Data.Length]; 325 for (int num14 = 0; num14 < value3.Data.Length; num14++) 326 { 327 array5[num14].X = leftRight + num14; 328 array5[num14].Y = ControlHelper.ComputePaintLocationY(value3.IsLeftFrame ? value_max_left : value_max_right, value3.IsLeftFrame ? value_min_left : value_min_right, height - upDowm - upDowm, value3.Data[num14]) + (float)upDowm; 329 DrawMarkPoint(graphics, value3.MarkText[num14], array5[num14], value3.LineColor, MarkText.CalculateDirectionFromDataIndex(value3.Data, num14)); 330 } 331 } 332 else 333 { 334 array5 = new PointF[num13]; 335 for (int num15 = 0; num15 < array5.Length; num15++) 336 { 337 int num16 = num15 + value3.Data.Length - num13; 338 array5[num15].X = leftRight + num15; 339 array5[num15].Y = ControlHelper.ComputePaintLocationY(value3.IsLeftFrame ? value_max_left : value_max_right, value3.IsLeftFrame ? value_min_left : value_min_right, height - upDowm - upDowm, value3.Data[num16]) + (float)upDowm; 340 DrawMarkPoint(graphics, value3.MarkText[num16], array5[num15], value3.LineColor, MarkText.CalculateDirectionFromDataIndex(value3.Data, num16)); 341 } 342 } 343 using (Pen pen3 = new Pen(value3.LineColor, value3.LineThickness)) 344 { 345 if (value3.IsSmoothCurve) 346 { 347 graphics.DrawCurve(pen3, array5); 348 } 349 else 350 { 351 graphics.DrawLines(pen3, array5); 352 } 353 } 354 } 355 } 356 } 357 } 358 base.OnPaint(e); 359 } 360 catch (Exception exc) 361 { 362 e.Graphics.DrawString(exc.Message, this.Font, Brushes.Black, 10, 10); 363 } 364 }
輔助函式
1 /// <summary> 2 /// Draws the mark point. 3 /// </summary> 4 /// <param name="g">The g.</param> 5 /// <param name="markText">The mark text.</param> 6 /// <param name="center">The center.</param> 7 /// <param name="color">The color.</param> 8 /// <param name="markTextPosition">The mark text position.</param> 9 private void DrawMarkPoint(Graphics g, string markText, PointF center, Color color, MarkTextPositionStyle markTextPosition) 10 { 11 if (!string.IsNullOrEmpty(markText)) 12 { 13 using (Brush brush = new SolidBrush(color)) 14 { 15 DrawMarkPoint(g, markText, center, brush, markTextPosition); 16 } 17 } 18 } 19 20 /// <summary> 21 /// Draws the mark point. 22 /// </summary> 23 /// <param name="g">The g.</param> 24 /// <param name="markText">The mark text.</param> 25 /// <param name="center">The center.</param> 26 /// <param name="brush">The brush.</param> 27 /// <param name="markTextPosition">The mark text position.</param> 28 private void DrawMarkPoint(Graphics g, string markText, PointF center, Brush brush, MarkTextPositionStyle markTextPosition) 29 { 30 if (!string.IsNullOrEmpty(markText)) 31 { 32 g.FillEllipse(brush, new RectangleF(center.X - 3f, center.Y - 3f, 6f, 6f)); 33 switch (markTextPosition) 34 { 35 case MarkTextPositionStyle.Left: 36 g.DrawString(markText, Font, brush, new RectangleF(center.X - 100f, center.Y - (float)Font.Height, 100 - MarkText.MarkTextOffect, Font.Height * 2), format_right); 37 break; 38 case MarkTextPositionStyle.Up: 39 g.DrawString(markText, Font, brush, new RectangleF(center.X - 100f, center.Y - (float)Font.Height - (float)MarkText.MarkTextOffect, 200f, Font.Height + 2), format_center); 40 break; 41 case MarkTextPositionStyle.Right: 42 g.DrawString(markText, Font, brush, new RectangleF(center.X + (float)MarkText.MarkTextOffect, center.Y - (float)Font.Height, 100f, Font.Height * 2), format_left); 43 break; 44 case MarkTextPositionStyle.Down: 45 g.DrawString(markText, Font, brush, new RectangleF(center.X - 100f, center.Y + (float)MarkText.MarkTextOffect, 200f, Font.Height + 2), format_center); 46 break; 47 } 48 } 49 } 50 51 /// <summary> 52 /// Determines whether [is need paint dash] [the specified paint value]. 53 /// </summary> 54 /// <param name="paintValue">The paint value.</param> 55 /// <returns><c>true</c> if [is need paint dash] [the specified paint value]; otherwise, <c>false</c>.</returns> 56 private bool IsNeedPaintDash(float paintValue) 57 { 58 for (int i = 0; i < auxiliary_lines.Count; i++) 59 { 60 if (Math.Abs(auxiliary_lines[i].PaintValue - paintValue) < (float)font_size9.Height) 61 { 62 return false; 63 } 64 } 65 return true; 66 } 67 68 /// <summary> 69 /// Calculates the data count by offect. 70 /// </summary> 71 /// <param name="offect">The offect.</param> 72 /// <returns>System.Int32.</returns> 73 private int CalculateDataCountByOffect(float offect) 74 { 75 if (value_IntervalAbscissaText > 0) 76 { 77 return value_IntervalAbscissaText; 78 } 79 if (offect > 40f) 80 { 81 return 1; 82 } 83 offect = 40f / offect; 84 return (int)Math.Ceiling(offect); 85 }
一些公開函式
1 /// <summary> 2 /// Sets the curve text. 3 /// </summary> 4 /// <param name="descriptions">The descriptions.</param> 5 public void SetCurveText(string[] descriptions) 6 { 7 data_text = descriptions; 8 Invalidate(); 9 } 10 11 /// <summary> 12 /// Sets the left curve. 13 /// </summary> 14 /// <param name="key">The key.</param> 15 /// <param name="data">The data.</param> 16 /// <param name="lineColor">Color of the line.</param> 17 public void SetLeftCurve(string key, float[] data, Color? lineColor = null) 18 { 19 SetCurve(key, true, data, lineColor, 1f, false); 20 } 21 22 /// <summary> 23 /// Sets the left curve. 24 /// </summary> 25 /// <param name="key">The key.</param> 26 /// <param name="data">The data.</param> 27 /// <param name="lineColor">Color of the line.</param> 28 /// <param name="isSmooth">if set to <c>true</c> [is smooth].</param> 29 public void SetLeftCurve(string key, float[] data, Color? lineColor, bool isSmooth = false) 30 { 31 SetCurve(key, true, data, lineColor, 1f, isSmooth); 32 } 33 34 /// <summary> 35 /// Sets the right curve. 36 /// </summary> 37 /// <param name="key">The key.</param> 38 /// <param name="data">The data.</param> 39 /// <param name="lineColor">Color of the line.</param> 40 public void SetRightCurve(string key, float[] data, Color? lineColor = null) 41 { 42 SetCurve(key, false, data, lineColor, 1f, false); 43 } 44 45 /// <summary> 46 /// Sets the right curve. 47 /// </summary> 48 /// <param name="key">The key.</param> 49 /// <param name="data">The data.</param> 50 /// <param name="lineColor">Color of the line.</param> 51 /// <param name="isSmooth">if set to <c>true</c> [is smooth].</param> 52 public void SetRightCurve(string key, float[] data, Color? lineColor, bool isSmooth = false) 53 { 54 SetCurve(key, false, data, lineColor, 1f, isSmooth); 55 } 56 57 /// <summary> 58 /// Sets the curve. 59 /// </summary> 60 /// <param name="key">The key.</param> 61 /// <param name="isLeft">if set to <c>true</c> [is left].</param> 62 /// <param name="data">The data.</param> 63 /// <param name="lineColor">Color of the line.</param> 64 /// <param name="thickness">The thickness.</param> 65 /// <param name="isSmooth">if set to <c>true</c> [is smooth].</param> 66 public void SetCurve(string key, bool isLeft, float[] data, Color? lineColor, float thickness, bool isSmooth) 67 { 68 if (data_list.ContainsKey(key)) 69 { 70 if (data == null) 71 { 72 data = new float[0]; 73 } 74 data_list[key].Data = data; 75 } 76 else 77 { 78 if (data == null) 79 { 80 data = new float[0]; 81 } 82 data_list.Add(key, new CurveItem 83 { 84 Data = data, 85 MarkText = new string[data.Length], 86 LineThickness = thickness, 87 LineColor = lineColor ?? ControlHelper.Colors[data_list.Count + 13], 88 IsLeftFrame = isLeft, 89 IsSmoothCurve = isSmooth 90 }); 91 if (data_text == null) 92 { 93 data_text = new string[data.Length]; 94 } 95 } 96 Invalidate(); 97 } 98 99 /// <summary> 100 /// Removes the curve. 101 /// </summary> 102 /// <param name="key">The key.</param> 103 public void RemoveCurve(string key) 104 { 105 if (data_list.ContainsKey(key)) 106 { 107 data_list.Remove(key); 108 } 109 if (data_list.Count == 0) 110 { 111 data_text = new string[0]; 112 } 113 Invalidate(); 114 } 115 116 /// <summary> 117 /// Removes all curve. 118 /// </summary> 119 public void RemoveAllCurve() 120 { 121 int count = data_list.Count; 122 data_list.Clear(); 123 if (data_list.Count == 0) 124 { 125 data_text = new string[0]; 126 } 127 if (count > 0) 128 { 129 Invalidate(); 130 } 131 } 132 133 /// <summary> 134 /// Removes all curve data. 135 /// </summary> 136 public void RemoveAllCurveData() 137 { 138 int count = data_list.Count; 139 foreach (KeyValuePair<string, CurveItem> item in data_list) 140 { 141 item.Value.Data = new float[0]; 142 item.Value.MarkText = new string[0]; 143 } 144 data_text = new string[0]; 145 if (count > 0) 146 { 147 Invalidate(); 148 } 149 } 150 151 /// <summary> 152 /// Gets the curve item. 153 /// </summary> 154 /// <param name="key">The key.</param> 155 /// <returns>CurveItem.</returns> 156 public CurveItem GetCurveItem(string key) 157 { 158 if (data_list.ContainsKey(key)) 159 { 160 return data_list[key]; 161 } 162 return null; 163 } 164 165 /// <summary> 166 /// Saves to bitmap. 167 /// </summary> 168 /// <returns>Bitmap.</returns> 169 public Bitmap SaveToBitmap() 170 { 171 return SaveToBitmap(base.Width, base.Height); 172 } 173 174 /// <summary> 175 /// Saves to bitmap. 176 /// </summary> 177 /// <param name="width">The width.</param> 178 /// <param name="height">The height.</param> 179 /// <returns>Bitmap.</returns> 180 public Bitmap SaveToBitmap(int width, int height) 181 { 182 Bitmap bitmap = new Bitmap(width, height); 183 Graphics graphics = Graphics.FromImage(bitmap); 184 OnPaint(new PaintEventArgs(graphics, new Rectangle(0, 0, width, height))); 185 return bitmap; 186 } 187 188 /// <summary> 189 /// Adds the curve data. 190 /// </summary> 191 /// <param name="key">The key.</param> 192 /// <param name="values">The values.</param> 193 /// <param name="markTexts">The mark texts.</param> 194 /// <param name="isUpdateUI">if set to <c>true</c> [is update UI].</param> 195 private void AddCurveData(string key, float[] values, string[] markTexts, bool isUpdateUI) 196 { 197 if ((values != null && values.Length < 1) || !data_list.ContainsKey(key)) 198 { 199 return; 200 } 201 CurveItem CurveItem = data_list[key]; 202 if (CurveItem.Data != null) 203 { 204 if (value_IsAbscissaStrech) 205 { 206 ControlHelper.AddArrayData(ref CurveItem.Data, values, value_StrechDataCountMax); 207 ControlHelper.AddArrayData(ref CurveItem.MarkText, markTexts, value_StrechDataCountMax); 208 } 209 else 210 { 211 ControlHelper.AddArrayData(ref CurveItem.Data, values, 4096); 212 ControlHelper.AddArrayData(ref CurveItem.MarkText, markTexts, 4096); 213 } 214 if (isUpdateUI) 215 { 216 Invalidate(); 217 } 218 } 219 } 220 221 /// <summary> 222 /// Adds the curve time. 223 /// </summary> 224 /// <param name="count">The count.</param> 225 private void AddCurveTime(int count) 226 { 227 AddCurveTime(count, DateTime.Now.ToString(textFormat)); 228 } 229 230 /// <summary> 231 /// Adds the curve time. 232 /// </summary> 233 /// <param name="count">The count.</param> 234 /// <param name="text">The text.</param> 235 private void AddCurveTime(int count, string text) 236 { 237 if (data_text != null) 238 { 239 string[] array = new string[count]; 240 for (int i = 0; i < array.Length; i++) 241 { 242 array[i] = text; 243 } 244 if (value_IsAbscissaStrech) 245 { 246 ControlHelper.AddArrayData(ref data_text, array, value_StrechDataCountMax); 247 } 248 else 249 { 250 ControlHelper.AddArrayData(ref data_text, array, 4096); 251 } 252 } 253 } 254 255 /// <summary> 256 /// Adds the curve data. 257 /// </summary> 258 /// <param name="key">The key.</param> 259 /// <param name="value">The value.</param> 260 public void AddCurveData(string key, float value) 261 { 262 AddCurveData(key, new float[1] 263 { 264 value 265 }); 266 } 267 268 /// <summary> 269 /// Adds the curve data. 270 /// </summary> 271 /// <param name="key">The key.</param> 272 /// <param name="value">The value.</param> 273 /// <param name="markText">The mark text.</param> 274 public void AddCurveData(string key, float value, string markText) 275 { 276 AddCurveData(key, new float[1] 277 { 278 value 279 }, new string[1] 280 { 281 markText 282 }); 283 } 284 285 /// <summary> 286 /// Adds the curve data. 287 /// </summary> 288 /// <param name="key">The key.</param> 289 /// <param name="values">The values.</param> 290 public void AddCurveData(string key, float[] values) 291 { 292 AddCurveData(key, values, null); 293 } 294 295 /// <summary> 296 /// Adds the curve data. 297 /// </summary> 298 /// <param name="key">The key.</param> 299 /// <param name="values">The values.</param> 300 /// <param name="markTexts">The mark texts.</param> 301 public void AddCurveData(string key, float[] values, string[] markTexts) 302 { 303 if (markTexts == null) 304 { 305 markTexts = new string[values.Length]; 306 } 307 AddCurveData(key, values, markTexts, false); 308 if (values != null && values.Length != 0) 309 { 310 AddCurveTime(values.Length); 311 } 312 Invalidate(); 313 } 314 315 /// <summary> 316 /// Adds the curve data. 317 /// </summary> 318 /// <param name="keys">The keys.</param> 319 /// <param name="values">The values.</param> 320 public void AddCurveData(string[] keys, float[] values) 321 { 322 AddCurveData(keys, values, null); 323 } 324 325 /// <summary> 326 /// Adds the curve data. 327 /// </summary> 328 /// <param name="axisText">The axis text.</param> 329 /// <param name="keys">The keys.</param> 330 /// <param name="values">The values.</param> 33