1 //------------------------------------------------------------- 2 // <copyright company=�Microsoft Corporation�> 3 // Copyright � Microsoft Corporation. All Rights Reserved. 4 // </copyright> 5 //------------------------------------------------------------- 6 // @owner=alexgor, deliant 7 //================================================================= 8 // File: AxisScrollZoom.cs 9 // 10 // Namespace: System.Web.UI.WebControls[Windows.Forms].Charting 11 // 12 // Classes: AxisScaleView, ViewEventArgs, DoubleNanValueConverter 13 // 14 // Purpose: AxisScaleView class represents a data scaleView, and is 15 // exposed using the Axis.ScaleView property. A data scaleView is 16 // a "scaleView" of data that has a start position (represented 17 // by the Position property) and a size (represented by 18 // the Size property). 19 // 20 // Axis data scaleView is used in zooming and scrolling when 21 // only part of the data must be visible. Views always 22 // belong to an axis, and a scaleView can result from either 23 // user interaction or by calling the Zoom or Scroll 24 // methods. User interaction, accomplished using range 25 // selection along an axis using the mouse, is possible 26 // if the IsUserSelectionEnabled property of the chart area' 27 // s cursor property is set to true. The end-user selects 28 // a range by left-clicking the mouse and dragging the 29 // mouse, and when the mouse button is released the 30 // selected range is then displayed as a scaleView. 31 // 32 // Reviewed: AG - Microsoft 16, 2007 33 // 34 //=================================================================== 35 36 #region Used namespace 37 38 using System; 39 using System.Drawing; 40 using System.Drawing.Drawing2D; 41 using System.ComponentModel; 42 using System.Collections; 43 using System.Globalization; 44 45 #if Microsoft_CONTROL 46 using System.Windows.Forms.DataVisualization.Charting; 47 using System.Windows.Forms.DataVisualization.Charting.Data; 48 using System.Windows.Forms.DataVisualization.Charting.ChartTypes; 49 using System.Windows.Forms.DataVisualization.Charting.Utilities; 50 using System.Windows.Forms.DataVisualization.Charting.Borders3D; 51 using System.Diagnostics.CodeAnalysis; 52 53 54 #else 55 using System.Web.UI.DataVisualization.Charting; 56 using System.Web.UI.DataVisualization.Charting.Utilities; 57 #endif 58 59 60 #endregion 61 62 #if Microsoft_CONTROL 63 namespace System.Windows.Forms.DataVisualization.Charting 64 #else 65 namespace System.Web.UI.DataVisualization.Charting 66 #endif 67 { 68 69 #region Scrolling enumerations 70 71 #if Microsoft_CONTROL 72 73 /// <summary> 74 /// Scrolling type enumeration. 75 /// </summary> 76 public enum ScrollType 77 { 78 /// <summary> 79 /// Scrolls by substracting one small size. 80 /// </summary> 81 SmallDecrement, 82 /// <summary> 83 /// Scrolls by adding one small size. 84 /// </summary> 85 SmallIncrement, 86 /// <summary> 87 /// Scrolls by substracting one scaleView size. 88 /// </summary> 89 LargeDecrement, 90 /// <summary> 91 /// Scrolls by adding one scaleView size. 92 /// </summary> 93 LargeIncrement, 94 /// <summary> 95 /// Scrolls to the first scaleView. 96 /// </summary> 97 First, 98 /// <summary> 99 /// Scrolls to the last scaleView. 100 /// </summary> 101 Last 102 } 103 104 #endif // Microsoft_CONTROL 105 106 #endregion 107 108 /// <summary> 109 /// AxisScaleView class represents a scale view which allows to display 110 /// only part of the available data. 111 /// </summary> 112 [ 113 SRDescription("DescriptionAttributeAxisDataView_AxisDataView"), 114 DefaultProperty("Position"), 115 ] 116 #if ASPPERM_35 117 [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] 118 [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] 119 #endif 120 public class AxisScaleView 121 { 122 #region Fields 123 124 // Reference to the axis object 125 internal Axis axis = null; 126 127 // Axis data scaleView position 128 private double _position = double.NaN; 129 130 // Axis data scaleView size 131 private double _size = double.NaN; 132 133 // Axis data scaleView size units type 134 private DateTimeIntervalType _sizeType = DateTimeIntervalType.Auto; 135 136 #if Microsoft_CONTROL 137 138 // Axis data scaleView minimum scaleView/scrolling size 139 private double _minSize = double.NaN; 140 141 // Axis data scaleView minimum scaleView/scrolling size units type 142 private DateTimeIntervalType _minSizeType = DateTimeIntervalType.Auto; 143 144 // Axis data scaleView zooming UI interface enabled flag 145 private bool _zoomable = true; 146 147 // Axis data scaleView scroll line size 148 private double _smallScrollSize = double.NaN; 149 150 // Axis data scaleView scroll line size units type 151 private DateTimeIntervalType _smallScrollSizeType = DateTimeIntervalType.Auto; 152 153 // Axis data scaleView scroll line minimum size 154 private double _smallScrollMinSize = 1.0; 155 156 // Axis data scaleView scroll line minimum size units type 157 private DateTimeIntervalType _smallScrollMinSizeType = DateTimeIntervalType.Auto; 158 159 // Axis data scaleView scroll line minimum size 160 private double _currentSmallScrollSize = double.NaN; 161 162 // Axis data scaleView scroll line minimum size units type 163 private DateTimeIntervalType _currentSmallScrollSizeType = DateTimeIntervalType.Auto; 164 165 // Storage for the saved data scaleView states (position/size/sizetype) 166 internal ArrayList dataViewStates = null; 167 168 #endif 169 170 // Ignore validation flag 171 private bool _ignoreValidation = false; 172 173 #endregion 174 175 #region Constructor 176 177 /// <summary> 178 /// Default constructor 179 /// </summary> AxisScaleView()180 public AxisScaleView() 181 { 182 this.axis = null; 183 } 184 185 /// <summary> 186 /// Internal constructor. 187 /// </summary> 188 /// <param name="axis">Data scaleView axis.</param> AxisScaleView(Axis axis)189 internal AxisScaleView(Axis axis) 190 { 191 this.axis = axis; 192 } 193 194 #endregion 195 196 #region Axis data scaleView properties 197 198 /// <summary> 199 /// Gets or sets the position of the AxisScaleView. 200 /// </summary> 201 [ 202 SRCategory("CategoryAttributeAxisView"), 203 Bindable(true), 204 DefaultValue(Double.NaN), 205 SRDescription("DescriptionAttributeAxisDataView_Position"), 206 TypeConverter(typeof(DoubleDateNanValueConverter)), 207 ParenthesizePropertyNameAttribute(true) 208 ] 209 public double Position 210 { 211 get 212 { 213 // Axis scaleView is not supported in circular chrt areas 214 if(this.axis != null && this.axis.ChartArea != null && this.axis.ChartArea.chartAreaIsCurcular) 215 { 216 return Double.NaN; 217 } 218 return _position; 219 } 220 set 221 { 222 // Axis scaleView is not supported in circular chrt areas 223 if(this.axis != null && this.axis.ChartArea != null && this.axis.ChartArea.chartAreaIsCurcular) 224 { 225 return; 226 } 227 228 if(_position != value) 229 { 230 // Set new position 231 _position = value; 232 233 // Align scaleView in connected areas 234 if(this.axis != null && this.axis.ChartArea != null && this.axis.Common != null && this.axis.Common.ChartPicture != null) 235 { 236 if(!this.axis.ChartArea.alignmentInProcess) 237 { 238 AreaAlignmentOrientations orientation = (this.axis.axisType == AxisName.X || this.axis.axisType== AxisName.X2) ? 239 AreaAlignmentOrientations.Vertical : AreaAlignmentOrientations.Horizontal; 240 this.axis.Common.ChartPicture.AlignChartAreasAxesView(this.axis.ChartArea, orientation); 241 } 242 } 243 244 // Validate chart 245 if(!_ignoreValidation && axis != null) 246 { 247 axis.Invalidate(); 248 } 249 } 250 } 251 } 252 253 /// <summary> 254 /// Gets or sets the size of the AxisScaleView 255 /// </summary> 256 [ 257 SRCategory("CategoryAttributeAxisView"), 258 Bindable(true), 259 DefaultValue(Double.NaN), 260 SRDescription("DescriptionAttributeAxisDataView_Size"), 261 TypeConverter(typeof(DoubleNanValueConverter)), 262 ParenthesizePropertyNameAttribute(true) 263 ] 264 public double Size 265 { 266 get 267 { 268 // Axis scaleView is not supported in circular chrt areas 269 if(this.axis != null && this.axis.ChartArea != null && this.axis.ChartArea.chartAreaIsCurcular) 270 { 271 return Double.NaN; 272 } 273 274 return _size; 275 } 276 set 277 { 278 // Axis scaleView is not supported in circular chrt areas 279 if(this.axis != null && this.axis.ChartArea != null && this.axis.ChartArea.chartAreaIsCurcular) 280 { 281 return; 282 } 283 284 if(_size != value) 285 { 286 // Set size value 287 _size = value; 288 289 290 // Align scaleView in connected areas 291 if(this.axis != null && this.axis.ChartArea != null && this.axis.Common != null && this.axis.Common.ChartPicture != null) 292 { 293 if(!this.axis.ChartArea.alignmentInProcess) 294 { 295 AreaAlignmentOrientations orientation = (this.axis.axisType == AxisName.X || this.axis.axisType== AxisName.X2) ? 296 AreaAlignmentOrientations.Vertical : AreaAlignmentOrientations.Horizontal; 297 this.axis.Common.ChartPicture.AlignChartAreasAxesView(this.axis.ChartArea, orientation); 298 } 299 } 300 #if Microsoft_CONTROL 301 // Reset current scrolling line size 302 this._currentSmallScrollSize = double.NaN; 303 #endif //Microsoft_CONTROL 304 // Validate chart 305 if(!_ignoreValidation && axis != null) 306 { 307 axis.Invalidate(); 308 } 309 } 310 } 311 } 312 313 /// <summary> 314 /// Gets or sets the unit of measurement of the Size property. 315 /// </summary> 316 [ 317 SRCategory("CategoryAttributeAxisView"), 318 Bindable(true), 319 DefaultValue(DateTimeIntervalType.Auto), 320 SRDescription("DescriptionAttributeAxisDataView_SizeType"), 321 ParenthesizePropertyNameAttribute(true) 322 ] 323 public DateTimeIntervalType SizeType 324 { 325 get 326 { 327 return _sizeType; 328 } 329 set 330 { 331 if(_sizeType != value) 332 { 333 // Set size type 334 _sizeType = (value != DateTimeIntervalType.NotSet) ? value : DateTimeIntervalType.Auto; 335 336 // Align scaleView in connected areas 337 if(this.axis != null && this.axis.ChartArea != null && this.axis.Common != null && this.axis.Common.ChartPicture != null) 338 { 339 if(!this.axis.ChartArea.alignmentInProcess) 340 { 341 AreaAlignmentOrientations orientation = (this.axis.axisType == AxisName.X || this.axis.axisType== AxisName.X2) ? 342 AreaAlignmentOrientations.Vertical : AreaAlignmentOrientations.Horizontal; 343 this.axis.Common.ChartPicture.AlignChartAreasAxesView(this.axis.ChartArea, orientation); 344 } 345 } 346 347 // Validate chart 348 if(!_ignoreValidation && axis != null) 349 { 350 axis.Invalidate(); 351 } 352 } 353 } 354 } 355 356 /// <summary> 357 /// Indicates if axis is zoomed-in. 358 /// </summary> 359 [ 360 SRCategory("CategoryAttributeAxisView"), 361 Bindable(false), 362 Browsable(false), 363 SRDescription("DescriptionAttributeAxisDataView_IsZoomed"), 364 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 365 SerializationVisibility(SerializationVisibility.Hidden), 366 ] 367 public bool IsZoomed 368 { 369 get 370 { 371 return ( 372 !double.IsNaN(this.Size) && 373 this.Size != 0.0 && 374 !double.IsNaN(this.Position)); 375 } 376 } 377 378 #if Microsoft_CONTROL 379 380 /// <summary> 381 /// Gets or sets the minimum size of the AxisScaleView. 382 /// </summary> 383 [ 384 SRCategory("CategoryAttributeAxisView"), 385 Bindable(true), 386 DefaultValue(Double.NaN), 387 SRDescription("DescriptionAttributeAxisDataView_MinSize"), 388 TypeConverter(typeof(DoubleNanValueConverter)) 389 ] 390 public double MinSize 391 { 392 get 393 { 394 return _minSize; 395 } 396 set 397 { 398 _minSize = value; 399 } 400 } 401 402 /// <summary> 403 /// Gets or sets the unit of measurement of the MinSize property. 404 /// </summary> 405 [ 406 SRCategory("CategoryAttributeAxisView"), 407 Bindable(true), 408 DefaultValue(DateTimeIntervalType.Auto), 409 SRDescription("DescriptionAttributeAxisDataView_MinSizeType"), 410 ] 411 public DateTimeIntervalType MinSizeType 412 { 413 get 414 { 415 return _minSizeType; 416 } 417 set 418 { 419 _minSizeType = (value != DateTimeIntervalType.NotSet) ? value : DateTimeIntervalType.Auto; 420 } 421 } 422 423 /// <summary> 424 /// Gets or sets a flag which indicates whether the zooming user interface is enabled. 425 /// </summary> 426 [ 427 SRCategory("CategoryAttributeAxisView"), 428 Bindable(true), 429 DefaultValue(true), 430 SRDescription("DescriptionAttributeAxisDataView_Zoomable"), 431 SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", 432 Justification="'Zoomable' is a commonly used term and generally well understood"), 433 ] 434 public bool Zoomable 435 { 436 get 437 { 438 return _zoomable; 439 } 440 set 441 { 442 _zoomable = value; 443 } 444 } 445 446 /// <summary> 447 /// Gets or sets the small scrolling size. 448 /// </summary> 449 [ 450 SRCategory("CategoryAttributeAxisView"), 451 Bindable(true), 452 DefaultValue(Double.NaN), 453 SRDescription("DescriptionAttributeAxisDataView_SmallScrollSize"), 454 TypeConverter(typeof(AxisMinMaxAutoValueConverter)) 455 ] 456 public double SmallScrollSize 457 { 458 get 459 { 460 return _smallScrollSize; 461 } 462 set 463 { 464 if(_smallScrollSize != value) 465 { 466 // Set size value 467 _smallScrollSize = value; 468 469 // Validate chart 470 if(!_ignoreValidation && axis != null) 471 { 472 axis.Invalidate(); 473 } 474 } 475 } 476 } 477 478 /// <summary> 479 /// Gets or sets the unit of measurement for the SmallScrollMinSize property 480 /// </summary> 481 [ 482 SRCategory("CategoryAttributeAxisView"), 483 Bindable(true), 484 DefaultValue(DateTimeIntervalType.Auto), 485 SRDescription("DescriptionAttributeAxisDataView_SmallScrollSizeType"), 486 ] 487 public DateTimeIntervalType SmallScrollSizeType 488 { 489 get 490 { 491 return _smallScrollSizeType; 492 } 493 set 494 { 495 if(_smallScrollSizeType != value) 496 { 497 // Set size type 498 _smallScrollSizeType = (value != DateTimeIntervalType.NotSet) ? value : DateTimeIntervalType.Auto; 499 500 // Validate chart 501 if(!_ignoreValidation && axis != null) 502 { 503 axis.Invalidate(); 504 } 505 } 506 } 507 } 508 509 /// <summary> 510 /// Gets or sets the minimum small scrolling size. 511 /// Only used if the small scrolling size is not set. 512 /// </summary> 513 [ 514 SRCategory("CategoryAttributeAxisView"), 515 Bindable(true), 516 DefaultValue(1.0), 517 SRDescription("DescriptionAttributeAxisDataView_SmallScrollMinSize") 518 ] 519 public double SmallScrollMinSize 520 { 521 get 522 { 523 return _smallScrollMinSize; 524 } 525 set 526 { 527 if(_smallScrollMinSize != value) 528 { 529 // Set size value 530 _smallScrollMinSize = value; 531 532 _currentSmallScrollSize = double.NaN; 533 534 // Validate chart 535 if(!_ignoreValidation && axis != null) 536 { 537 axis.Invalidate(); 538 } 539 } 540 } 541 } 542 543 /// <summary> 544 /// Gets or sets the unit of measurement for the SmallScrollMinSize property. 545 /// </summary> 546 [ 547 SRCategory("CategoryAttributeAxisView"), 548 Bindable(true), 549 DefaultValue(DateTimeIntervalType.Auto), 550 SRDescription("DescriptionAttributeAxisDataView_SmallScrollMinSizeType"), 551 ] 552 public DateTimeIntervalType SmallScrollMinSizeType 553 { 554 get 555 { 556 return _smallScrollMinSizeType; 557 } 558 set 559 { 560 if(_smallScrollMinSizeType != value) 561 { 562 // Set size type 563 _smallScrollMinSizeType = (value != DateTimeIntervalType.NotSet) ? value : DateTimeIntervalType.Auto; 564 565 _currentSmallScrollSize = double.NaN; 566 567 // Validate chart 568 if(!_ignoreValidation && axis != null) 569 { 570 axis.Invalidate(); 571 } 572 } 573 } 574 } 575 576 #endif // Microsoft_CONTROL 577 578 #endregion 579 580 #region ScaleView position internal methods 581 582 /// <summary> 583 /// Call this method to get the minimum axis value of a data view. 584 /// </summary> 585 /// <returns>The minimum axis value for the data view.</returns> 586 [Browsable(false)] 587 [Utilities.SerializationVisibility(Utilities.SerializationVisibility.Hidden)] 588 public double ViewMinimum 589 { 590 get 591 { 592 // If zooming is enabled 593 if (!Double.IsNaN(this.Size)) 594 { 595 // If size set only use axis minimum for scaleView position 596 if (Double.IsNaN(this.Position)) 597 { 598 this.Position = this.axis.Minimum; 599 } 600 // Check if scaleView position and size are set 601 else 602 { 603 // Calculate and add axis side margin 604 if (this.Position <= axis.minimum) 605 { 606 return this.Position; 607 } 608 else // Add a margin only if scaleView is inside data point scaleView 609 { 610 return this.Position - axis.marginView; 611 } 612 } 613 } 614 615 // Return axis scale minimum value if scaleView position is not set 616 return axis.minimum; 617 } 618 } 619 620 /// <summary> 621 /// Maximum axis value of a data view. 622 /// </summary> 623 /// <returns>The maximum axis value for the data view.</returns> 624 [Browsable(false)] 625 [Utilities.SerializationVisibility(Utilities.SerializationVisibility.Hidden)] 626 public double ViewMaximum 627 { 628 get 629 { 630 // If zooming is enabled 631 if (!Double.IsNaN(this.Size)) 632 { 633 // If size set only use axis minimum for scaleView position 634 if (Double.IsNaN(this.Position)) 635 { 636 this.Position = this.axis.Minimum; 637 } 638 639 // Check if scaleView position and size are set 640 else 641 { 642 // Get axis interval 643 double viewSize = ChartHelper.GetIntervalSize(this.Position, this.Size, this.SizeType); 644 645 // Calculate and add axis side margin 646 if (this.Position + viewSize >= axis.maximum) 647 { 648 return this.Position + viewSize; 649 } 650 else // Add a margin only if scaleView is inside data point scaleView 651 { 652 return this.Position + viewSize + axis.marginView; 653 } 654 } 655 } 656 657 // Return axis scale maximum value if scaleView position is not set 658 return axis.maximum; 659 } 660 } 661 662 #endregion 663 664 #region Scrolling methods 665 666 #if Microsoft_CONTROL 667 668 /// <summary> 669 /// Call this method to scroll to a specified position along an axis. 670 /// </summary> 671 /// <param name="scrollType">Direction and size to scroll.</param> Scroll(ScrollType scrollType)672 public void Scroll(ScrollType scrollType) 673 { 674 this.Scroll(scrollType, false); 675 } 676 677 /// <summary> 678 /// Scrolls axis data scaleView from current position. 679 /// </summary> 680 /// <param name="scrollType">Direction and size to scroll.</param> 681 /// <param name="fireChangeEvents">Fire scaleView position events from this method.</param> Scroll(ScrollType scrollType, bool fireChangeEvents)682 internal void Scroll(ScrollType scrollType, bool fireChangeEvents) 683 { 684 // Adjust current position depending on the scroll type 685 double newPosition = this._position; 686 switch(scrollType) 687 { 688 case(ScrollType.SmallIncrement): 689 newPosition += ((axis.IsReversed) ? -1 : 1) * ChartHelper.GetIntervalSize(this._position, this.GetScrollingLineSize(), this.GetScrollingLineSizeType()); 690 break; 691 case(ScrollType.SmallDecrement): 692 newPosition -= ((axis.IsReversed) ? -1 : 1) * ChartHelper.GetIntervalSize(this._position, this.GetScrollingLineSize(), this.GetScrollingLineSizeType()); 693 break; 694 case(ScrollType.LargeIncrement): 695 newPosition += ((axis.IsReversed) ? -1 : 1) * ChartHelper.GetIntervalSize(this._position, this.Size, this.SizeType); 696 break; 697 case(ScrollType.LargeDecrement): 698 newPosition -= ((axis.IsReversed) ? -1 : 1) * ChartHelper.GetIntervalSize(this._position, this.Size, this.SizeType); 699 break; 700 case(ScrollType.First): 701 if(!axis.IsReversed) 702 { 703 newPosition = (axis.minimum + axis.marginView); 704 } 705 else 706 { 707 newPosition = (axis.maximum - axis.marginView); 708 } 709 break; 710 case(ScrollType.Last): 711 { 712 double viewSize = ChartHelper.GetIntervalSize(newPosition, this.Size, this.SizeType); 713 if(!axis.IsReversed) 714 { 715 newPosition = (axis.maximum - axis.marginView - viewSize); 716 } 717 else 718 { 719 newPosition = (axis.minimum + axis.marginView + viewSize); 720 } 721 break; 722 } 723 } 724 725 // Scroll to the new position 726 this.Scroll(newPosition, fireChangeEvents); 727 } 728 729 /// <summary> 730 /// Call this method to scroll to a specified position along an axis. 731 /// </summary> 732 /// <param name="newPosition">New position.</param> Scroll(double newPosition)733 public void Scroll(double newPosition) 734 { 735 this.Scroll(newPosition, false); 736 } 737 738 /// <summary> 739 /// Call this method to scroll to a specified position along an axis. 740 /// </summary> 741 /// <param name="newPosition">New position.</param> Scroll(DateTime newPosition)742 public void Scroll(DateTime newPosition) 743 { 744 this.Scroll(newPosition.ToOADate(), false); 745 } 746 747 /// <summary> 748 /// Internal helper method for scrolling into specified position. 749 /// </summary> 750 /// <param name="newPosition">New data scaleView position.</param> 751 /// <param name="fireChangeEvents">Fire scaleView position events from this method.</param> Scroll(double newPosition, bool fireChangeEvents)752 internal void Scroll(double newPosition, bool fireChangeEvents) 753 { 754 // Get current scaleView size 755 double viewSize = ChartHelper.GetIntervalSize(newPosition, this.Size, this.SizeType); 756 757 // Validate new scaleView position 758 if(newPosition < (axis.minimum + axis.marginView)) 759 { 760 newPosition = (axis.minimum + axis.marginView); 761 } 762 else if(newPosition > (axis.maximum - axis.marginView - viewSize)) 763 { 764 newPosition = (axis.maximum - axis.marginView - viewSize); 765 } 766 767 // Fire scaleView position changing events 768 ViewEventArgs arguments = new ViewEventArgs(this.axis, newPosition, this.Size, this.SizeType); 769 if(fireChangeEvents && GetChartObject() != null) 770 { 771 GetChartObject().OnAxisViewChanging(arguments); 772 newPosition = arguments.NewPosition; 773 } 774 775 // Check if data scaleView position and size is different from current 776 if(newPosition == this.Position) 777 { 778 return; 779 } 780 781 // Change scaleView position 782 this.Position = newPosition; 783 784 // Fire scaleView position changed events 785 if(fireChangeEvents && GetChartObject() != null) 786 { 787 GetChartObject().OnAxisViewChanged(arguments); 788 } 789 } 790 791 #endif 792 #endregion 793 794 #region Zooming and ZoomResetting methods 795 796 #if Microsoft_CONTROL 797 798 /// <summary> 799 /// Sets a new axis data view/position based on the start and end dates specified. 800 /// </summary> 801 /// <param name="viewPosition">New start position for the axis scale view.</param> 802 /// <param name="viewSize">New size for the axis scale view.</param> 803 /// <param name="viewSizeType">New unit of measurement of the size.</param> 804 /// <param name="saveState">Indicates whether the current size/position needs to be saved.</param> Zoom(double viewPosition, double viewSize, DateTimeIntervalType viewSizeType, bool saveState)805 public void Zoom(double viewPosition, double viewSize, DateTimeIntervalType viewSizeType, bool saveState) 806 { 807 this.Zoom(viewPosition, viewSize, viewSizeType, false, saveState); 808 } 809 810 /// <summary> 811 /// Sets a new axis data view/position based on the specified start and end values. 812 /// </summary> 813 /// <param name="viewStart">New start position for the axis scale view.</param> 814 /// <param name="viewEnd">New end position for the axis scale view.</param> Zoom(double viewStart, double viewEnd)815 public void Zoom(double viewStart, double viewEnd) 816 { 817 this.Zoom(viewStart, viewEnd - viewStart, DateTimeIntervalType.Number, false, false); 818 } 819 820 /// <summary> 821 /// Sets a new axis data view/position based on the start and end dates specified. 822 /// </summary> 823 /// <param name="viewPosition">New start position for the axis scale view.</param> 824 /// <param name="viewSize">New size for the axis scale view.</param> 825 /// <param name="viewSizeType">New unit of measurement of the size.</param> Zoom(double viewPosition, double viewSize, DateTimeIntervalType viewSizeType)826 public void Zoom(double viewPosition, double viewSize, DateTimeIntervalType viewSizeType) 827 { 828 this.Zoom(viewPosition, viewSize, viewSizeType, false, false); 829 } 830 831 /// <summary> 832 /// Reset the specified number of zooming operations by restoring axis data view. 833 /// </summary> 834 /// <param name="numberOfViews">Number of zoom operations to reset. Zero for all.</param> ZoomReset(int numberOfViews)835 public void ZoomReset(int numberOfViews) 836 { 837 this.LoadDataViewState(numberOfViews, false); 838 } 839 840 /// <summary> 841 /// Reset one zooming operation by restoring axis data view. 842 /// </summary> ZoomReset()843 public void ZoomReset() 844 { 845 this.LoadDataViewState(1, false); 846 } 847 848 /// <summary> 849 /// Reset several zooming operation by restoring data scaleView size/position. 850 /// </summary> 851 /// <param name="numberOfViews">How many scaleView zoom operations to reset. Zero for all.</param> 852 /// <param name="fireChangeEvents">Fire scaleView position events from this method.</param> ZoomReset(int numberOfViews, bool fireChangeEvents)853 internal void ZoomReset(int numberOfViews, bool fireChangeEvents) 854 { 855 this.LoadDataViewState(numberOfViews, fireChangeEvents); 856 } 857 858 /// <summary> 859 /// Internal helper zooming method. 860 /// </summary> 861 /// <param name="viewPosition">New data scaleView start posiion.</param> 862 /// <param name="viewSize">New data scaleView size.</param> 863 /// <param name="viewSizeType">New data scaleView size units type.</param> 864 /// <param name="fireChangeEvents">Fire scaleView position events from this method.</param> 865 /// <param name="saveState">Indicates that current scaleView size/position must be save, so it can be restored later.</param> 866 /// <returns>True if zoom operation was made.</returns> Zoom( double viewPosition, double viewSize, DateTimeIntervalType viewSizeType, bool fireChangeEvents, bool saveState)867 internal bool Zoom( 868 double viewPosition, 869 double viewSize, 870 DateTimeIntervalType viewSizeType, 871 bool fireChangeEvents, 872 bool saveState) 873 { 874 // Validate new scaleView position and size 875 ValidateViewPositionSize(ref viewPosition, ref viewSize, ref viewSizeType); 876 877 // Fire scaleView position/size changing events 878 ViewEventArgs arguments = new ViewEventArgs(this.axis, viewPosition, viewSize, viewSizeType); 879 if(fireChangeEvents && GetChartObject() != null) 880 { 881 GetChartObject().OnAxisViewChanging(arguments); 882 viewPosition = arguments.NewPosition; 883 viewSize = arguments.NewSize; 884 viewSizeType = arguments.NewSizeType; 885 } 886 887 // Check if data scaleView position and size is different from current 888 if(viewPosition == this.Position && 889 viewSize == this.Size && 890 viewSizeType == this.SizeType) 891 { 892 return false; 893 } 894 895 // Save current data scaleView state, so it can be restored 896 if(saveState) 897 { 898 SaveDataViewState(); 899 } 900 901 // Change scaleView position/size 902 this._ignoreValidation = true; 903 this.Position = viewPosition; 904 this.Size = viewSize; 905 this.SizeType = viewSizeType; 906 this._ignoreValidation = false; 907 908 // Reset current scrolling line size 909 this._currentSmallScrollSize = double.NaN; 910 911 // Invalidate chart 912 axis.Invalidate(); 913 914 // Fire scaleView position/size changed events 915 if(fireChangeEvents && GetChartObject() != null) 916 { 917 GetChartObject().OnAxisViewChanged(arguments); 918 } 919 920 return true; 921 } 922 923 #endif 924 925 #endregion 926 927 #region Data scaleView state saving/restoring methods 928 929 #if Microsoft_CONTROL 930 931 /// <summary> 932 /// Saves current data scaleView position/size/sizetype, so 933 /// it can be restored later. 934 /// </summary> 935 /// <param name="numberOfViews">Number of time to reset zoom. Zero for all.</param> 936 /// <param name="fireChangeEvents">Fire scaleView position events from this method.</param> LoadDataViewState(int numberOfViews, bool fireChangeEvents)937 private void LoadDataViewState(int numberOfViews, bool fireChangeEvents) 938 { 939 // Check parameters 940 if(numberOfViews < 0) 941 { 942 throw (new ArgumentOutOfRangeException("numberOfViews", SR.ExceptionScrollBarZoomResetsNumberInvalid)); 943 } 944 // Check if storage was created 945 if(dataViewStates != null && dataViewStates.Count >= 3) 946 { 947 // Find starting index of restoring state 948 int dataStartIndex = 0; 949 if(numberOfViews > 0) 950 { 951 dataStartIndex = dataViewStates.Count - numberOfViews * 3; 952 if(dataStartIndex < 0) 953 { 954 dataStartIndex = 0; 955 } 956 } 957 958 959 // Fire scaleView position/size changing events 960 ViewEventArgs arguments = new ViewEventArgs( 961 this.axis, 962 (double)dataViewStates[dataStartIndex], 963 (double)dataViewStates[dataStartIndex + 1], 964 (DateTimeIntervalType)dataViewStates[dataStartIndex + 2]); 965 if(fireChangeEvents && GetChartObject() != null) 966 { 967 GetChartObject().OnAxisViewChanging(arguments); 968 } 969 970 // Restore data 971 this.Position = arguments.NewPosition; 972 this.Size = arguments.NewSize; 973 this.SizeType = arguments.NewSizeType; 974 975 // Fire scaleView position/size changed events 976 if(fireChangeEvents && GetChartObject() != null) 977 { 978 GetChartObject().OnAxisViewChanged(arguments); 979 } 980 981 // Clear data 982 int itemsToRemove = numberOfViews * 3; 983 if (itemsToRemove > (dataViewStates.Count - dataStartIndex)) 984 { 985 itemsToRemove = dataViewStates.Count - dataStartIndex; 986 } 987 dataViewStates.RemoveRange(dataStartIndex, itemsToRemove); 988 989 990 // clean up the history state when the numberOfViews == 0 (reset all by docs) 991 if ( numberOfViews == 0 ) 992 { 993 dataViewStates.Clear(); 994 } 995 if (Double.IsNaN(this.Position) || Double.IsNaN(this.Size)) 996 { 997 this.Position = Double.NaN; 998 this.Size = Double.NaN; 999 } 1000 1001 } 1002 1003 // Nothing to restore - just disable the data scaleView 1004 else 1005 { 1006 // Fire scaleView position/size changing events 1007 ViewEventArgs arguments = new ViewEventArgs( 1008 this.axis, 1009 double.NaN, 1010 double.NaN, 1011 DateTimeIntervalType.Auto); 1012 1013 if(fireChangeEvents && GetChartObject() != null) 1014 { 1015 GetChartObject().OnAxisViewChanging(arguments); 1016 } 1017 1018 // Restore data 1019 this.Position = arguments.NewPosition; 1020 this.Size = arguments.NewSize; 1021 this.SizeType = arguments.NewSizeType; 1022 1023 // Fire scaleView position/size changed events 1024 if(fireChangeEvents && GetChartObject() != null) 1025 { 1026 GetChartObject().OnAxisViewChanged(arguments); 1027 } 1028 } 1029 // clear cached chart areas and bitmap buffers 1030 GetChartObject().Refresh(); 1031 } 1032 1033 /// <summary> 1034 /// Saves current data scaleView position/size/sizetype, so 1035 /// it can be restored later. 1036 /// </summary> SaveDataViewState()1037 private void SaveDataViewState() 1038 { 1039 // Create storage array 1040 if(dataViewStates == null) 1041 { 1042 dataViewStates = new ArrayList(); 1043 } 1044 1045 // Save data scaleView state 1046 dataViewStates.Add(this.Position); 1047 dataViewStates.Add(this.Size); 1048 dataViewStates.Add(this.SizeType); 1049 } 1050 #endif 1051 1052 #endregion 1053 1054 #region Helper methods 1055 1056 #if Microsoft_CONTROL 1057 /// <summary> 1058 /// Initialize internal scrolling line size variables for later use. 1059 /// This size is used in to scroll chart one line up or down. 1060 /// </summary> GetCurrentViewSmallScrollSize()1061 private void GetCurrentViewSmallScrollSize() 1062 { 1063 //************************************************************************** 1064 //** Check if current scrolling line size was not already calculated 1065 //************************************************************************** 1066 if(double.IsNaN(_currentSmallScrollSize)) 1067 { 1068 //************************************************************************** 1069 //** Calculate line size depending on the current scaleView size 1070 //************************************************************************** 1071 if(this.SizeType == DateTimeIntervalType.Auto || this.SizeType == DateTimeIntervalType.Number) 1072 { 1073 // Set line size type 1074 _currentSmallScrollSizeType = DateTimeIntervalType.Number; 1075 1076 // Devide scaleView by 20 to find the scrolling line size 1077 double newSize = this.Size / 20.0; 1078 1079 // Make sure that current line size is even with minimum value 1080 if(!double.IsNaN(this.SmallScrollMinSize) && this.SmallScrollMinSize != 0.0) 1081 { 1082 double rounder = (Math.Round(newSize / this.SmallScrollMinSize)); 1083 if(rounder < 0) 1084 { 1085 rounder = 1; 1086 } 1087 newSize = rounder * this.SmallScrollMinSize; 1088 } 1089 1090 // Set new current line size 1091 this._currentSmallScrollSize = newSize; 1092 } 1093 else 1094 { 1095 // Calculate line size for date/time 1096 double viewEndPosition = this.Position + ChartHelper.GetIntervalSize(this.Position, this.Size, this.SizeType); 1097 _currentSmallScrollSize = axis.CalcInterval( 1098 this.Position, 1099 viewEndPosition, 1100 true, 1101 out _currentSmallScrollSizeType, 1102 ChartValueType.Auto); 1103 } 1104 1105 //************************************************************************** 1106 //** Make sure calculated scroll line size is not smaller than the minimum 1107 //************************************************************************** 1108 if(!double.IsNaN(this.SmallScrollMinSize) && this.SmallScrollMinSize != 0.0) 1109 { 1110 double newLineSize = ChartHelper.GetIntervalSize(this.Position, _currentSmallScrollSize, _currentSmallScrollSizeType); 1111 double minLineSize = ChartHelper.GetIntervalSize(this.Position, this.SmallScrollMinSize, this.SmallScrollMinSizeType); 1112 if(newLineSize < minLineSize) 1113 { 1114 _currentSmallScrollSize = SmallScrollMinSize; 1115 _currentSmallScrollSizeType = SmallScrollMinSizeType; 1116 } 1117 } 1118 } 1119 } 1120 1121 /// <summary> 1122 /// Returns the scroll line size. 1123 /// </summary> 1124 /// <returns>Scroll line size.</returns> GetScrollingLineSize()1125 internal double GetScrollingLineSize() 1126 { 1127 // Scroll line size/type is specificly set by user 1128 if(!double.IsNaN(this.SmallScrollSize)) 1129 { 1130 return this.SmallScrollSize; 1131 } 1132 1133 // Calcualte scroll line size depending on the current scaleView size 1134 GetCurrentViewSmallScrollSize(); 1135 1136 // Return line size 1137 return _currentSmallScrollSize; 1138 } 1139 1140 /// <summary> 1141 /// Returns the scroll line size units type. 1142 /// </summary> 1143 /// <returns>Scroll line size units type.</returns> GetScrollingLineSizeType()1144 internal DateTimeIntervalType GetScrollingLineSizeType() 1145 { 1146 // Scroll line size/type is specificly set by user 1147 if(!double.IsNaN(this.SmallScrollSize)) 1148 { 1149 return this.SmallScrollSizeType; 1150 } 1151 1152 // Calcualte scroll line size depending on the current scaleView size 1153 GetCurrentViewSmallScrollSize(); 1154 1155 // Return line size units type 1156 return _currentSmallScrollSizeType; 1157 } 1158 1159 /// <summary> 1160 /// Helper method, which validates the axis data scaleView position and size. 1161 /// Returns adjusted scaleView position and size. 1162 /// </summary> 1163 /// <param name="viewPosition">ScaleView position.</param> 1164 /// <param name="viewSize">ScaleView size.</param> 1165 /// <param name="viewSizeType">ScaleView size units type.</param> ValidateViewPositionSize(ref double viewPosition, ref double viewSize, ref DateTimeIntervalType viewSizeType)1166 private void ValidateViewPositionSize(ref double viewPosition, ref double viewSize, ref DateTimeIntervalType viewSizeType) 1167 { 1168 //**************************************************************** 1169 //** Check if new scaleView position is inside axis scale 1170 //** minimum/maximum without margin. 1171 //**************************************************************** 1172 if(viewPosition < (axis.minimum + axis.marginView)) 1173 { 1174 if(viewSizeType == DateTimeIntervalType.Auto || viewSizeType == DateTimeIntervalType.Number) 1175 { 1176 viewSize -= (axis.minimum + axis.marginView) - viewPosition; 1177 } 1178 viewPosition = (axis.minimum + axis.marginView); 1179 } 1180 else if(viewPosition > (axis.maximum - axis.marginView)) 1181 { 1182 if(viewSizeType == DateTimeIntervalType.Auto || viewSizeType == DateTimeIntervalType.Number) 1183 { 1184 viewSize -= viewPosition - (axis.maximum - axis.marginView); 1185 } 1186 viewPosition = (axis.maximum - axis.marginView); 1187 } 1188 1189 //**************************************************************** 1190 //** Check if new scaleView size is not smaller than minimum size 1191 //** set by the user 1192 //**************************************************************** 1193 double newViewSize = ChartHelper.GetIntervalSize(viewPosition, viewSize, viewSizeType); 1194 double minViewSize = ChartHelper.GetIntervalSize(viewPosition, 1, this.MinSizeType); 1195 if(!double.IsNaN(this.MinSize)) 1196 { 1197 minViewSize = ChartHelper.GetIntervalSize(viewPosition, this.MinSize, this.MinSizeType); 1198 if(newViewSize < minViewSize) 1199 { 1200 viewSize = (double.IsNaN(this.MinSize)) ? 1 : this.MinSize; 1201 viewSizeType = this.MinSizeType; 1202 newViewSize = ChartHelper.GetIntervalSize(viewPosition, viewSize, viewSizeType); 1203 } 1204 } 1205 1206 //**************************************************************** 1207 //** Check if new scaleView size is smaller than (0.000000001) 1208 //**************************************************************** 1209 if(newViewSize < 0.000000001) 1210 { 1211 viewSize = 0.000000001; 1212 viewSizeType = DateTimeIntervalType.Number; 1213 newViewSize = ChartHelper.GetIntervalSize(viewPosition, viewSize, viewSizeType); 1214 } 1215 1216 //**************************************************************** 1217 //** Check if new scaleView end position (position + size) is inside 1218 //** axis scale minimum/maximum without margin. 1219 //**************************************************************** 1220 while( (viewPosition + newViewSize) > (axis.maximum - axis.marginView) ) 1221 { 1222 double currentSize = viewSize; 1223 DateTimeIntervalType currentSizeType = viewSizeType; 1224 1225 // Try to reduce the scaleView size 1226 if(newViewSize > minViewSize) 1227 { 1228 // Try to adjust the scaleView size 1229 if(viewSize > 1) 1230 { 1231 --viewSize; 1232 } 1233 else if(viewSizeType == DateTimeIntervalType.Years) 1234 { 1235 viewSize = 11; 1236 viewSizeType = DateTimeIntervalType.Months; 1237 } 1238 else if(viewSizeType == DateTimeIntervalType.Months) 1239 { 1240 viewSize = 4; 1241 viewSizeType = DateTimeIntervalType.Weeks; 1242 } 1243 else if(viewSizeType == DateTimeIntervalType.Weeks) 1244 { 1245 viewSize = 6; 1246 viewSizeType = DateTimeIntervalType.Days; 1247 } 1248 else if(viewSizeType == DateTimeIntervalType.Days) 1249 { 1250 viewSize = 23; 1251 viewSizeType = DateTimeIntervalType.Hours; 1252 } 1253 else if(viewSizeType == DateTimeIntervalType.Hours) 1254 { 1255 viewSize = 59; 1256 viewSizeType = DateTimeIntervalType.Minutes; 1257 } 1258 else if(viewSizeType == DateTimeIntervalType.Minutes) 1259 { 1260 viewSize = 59; 1261 viewSizeType = DateTimeIntervalType.Seconds; 1262 } 1263 else if(viewSizeType == DateTimeIntervalType.Seconds) 1264 { 1265 viewSize = 999; 1266 viewSizeType = DateTimeIntervalType.Milliseconds; 1267 } 1268 else 1269 { 1270 viewPosition = (axis.maximum - axis.marginView) - minViewSize; 1271 break; 1272 } 1273 1274 // Double check that scaleView size is not smaller than min size 1275 newViewSize = ChartHelper.GetIntervalSize(viewPosition, viewSize, viewSizeType); 1276 if(newViewSize < minViewSize) 1277 { 1278 // Can't adjust size no more (restore prev. value) 1279 viewSize = currentSize; 1280 viewSizeType = currentSizeType; 1281 1282 // Adjust the start position 1283 viewPosition = (axis.maximum - axis.marginView) - minViewSize; 1284 break; 1285 } 1286 } 1287 else 1288 { 1289 // Adjust the start position 1290 viewPosition = (axis.maximum - axis.marginView) - newViewSize; 1291 break; 1292 } 1293 } 1294 } 1295 1296 /// <summary> 1297 /// Helper function which returns a reference to the chart object. 1298 /// </summary> 1299 /// <returns>Chart object reference.</returns> GetChartObject()1300 internal Chart GetChartObject() 1301 { 1302 if(this.axis != null && this.axis.Common!=null) 1303 { 1304 return this.axis.Common.Chart; 1305 } 1306 1307 return null; 1308 } 1309 #endif //Microsoft_CONTROL 1310 1311 #endregion 1312 } 1313 1314 #if Microsoft_CONTROL 1315 1316 /// <summary> 1317 /// This class is used as a parameter object in the AxisViewChanged and AxisViewChanging events of the root Chart object. 1318 /// </summary> 1319 public class ViewEventArgs : EventArgs 1320 { 1321 #region Private fields 1322 1323 // Private fields for properties values storage 1324 private Axis _axis = null; 1325 private double _newPosition = double.NaN; 1326 private double _newSize = double.NaN; 1327 private DateTimeIntervalType _newSizeType = DateTimeIntervalType.Auto; 1328 1329 #endregion 1330 1331 #region Constructors 1332 1333 /// <summary> 1334 /// ViewEventArgs constructor. 1335 /// </summary> 1336 /// <param name="axis">Axis of the scale view.</param> 1337 /// <param name="newPosition">New scale view start position.</param> ViewEventArgs(Axis axis, double newPosition)1338 public ViewEventArgs(Axis axis, double newPosition) 1339 { 1340 this._axis = axis; 1341 this._newPosition = newPosition; 1342 } 1343 1344 /// <summary> 1345 /// ViewEventArgs constructor. 1346 /// </summary> 1347 /// <param name="axis">Axis of the scale view.</param> 1348 /// <param name="newPosition">New scale view start position.</param> 1349 /// <param name="newSize">New scale view size.</param> 1350 /// <param name="newSizeType">New unit of measurement of the size.</param> ViewEventArgs(Axis axis, double newPosition, double newSize, DateTimeIntervalType newSizeType)1351 public ViewEventArgs(Axis axis, double newPosition, double newSize, DateTimeIntervalType newSizeType) 1352 { 1353 this._axis = axis; 1354 this._newPosition = newPosition; 1355 this._newSize = newSize; 1356 this._newSizeType = newSizeType; 1357 } 1358 1359 #endregion 1360 1361 #region Properties 1362 1363 /// <summary> 1364 /// Axis of the event. 1365 /// </summary> 1366 [ 1367 SRDescription("DescriptionAttributeAxis"), 1368 ] 1369 public Axis Axis 1370 { 1371 get 1372 { 1373 return _axis; 1374 } 1375 } 1376 1377 /// <summary> 1378 /// ChartArea of the event. 1379 /// </summary> 1380 [ 1381 SRDescription("DescriptionAttributeChartArea"), 1382 ] 1383 public ChartArea ChartArea 1384 { 1385 get 1386 { 1387 return _axis.ChartArea; 1388 } 1389 } 1390 1391 /// <summary> 1392 /// New scale view start position. 1393 /// </summary> 1394 [ 1395 SRDescription("DescriptionAttributeViewEventArgs_NewPosition"), 1396 ] 1397 public double NewPosition 1398 { 1399 get 1400 { 1401 return _newPosition; 1402 } 1403 set 1404 { 1405 _newPosition = value; 1406 } 1407 } 1408 1409 /// <summary> 1410 /// New scale view size. 1411 /// </summary> 1412 [ 1413 SRDescription("DescriptionAttributeViewEventArgs_NewSize"), 1414 ] 1415 public double NewSize 1416 { 1417 get 1418 { 1419 return _newSize; 1420 } 1421 set 1422 { 1423 _newSize = value; 1424 } 1425 } 1426 1427 /// <summary> 1428 /// New unit of measurement of the scale view. 1429 /// </summary> 1430 [ 1431 SRDescription("DescriptionAttributeViewEventArgs_NewSizeType"), 1432 ] 1433 public DateTimeIntervalType NewSizeType 1434 { 1435 get 1436 { 1437 return _newSizeType; 1438 } 1439 set 1440 { 1441 _newSizeType = (value != DateTimeIntervalType.NotSet) ? value : DateTimeIntervalType.Auto; 1442 } 1443 } 1444 1445 #endregion 1446 } 1447 1448 #endif // #if Microsoft_CONTROL 1449 } 1450 1451 #if Microsoft_CONTROL 1452 namespace System.Windows.Forms.DataVisualization.Charting 1453 #else 1454 namespace System.Web.UI.DataVisualization.Charting 1455 #endif 1456 { 1457 /// <summary> 1458 /// Designer converter class 1459 /// Converts Double.NaN values to/from "Not set". 1460 /// </summary> 1461 internal class DoubleNanValueConverter : DoubleConverter 1462 { 1463 #region Converter methods 1464 1465 /// <summary> 1466 /// Standard values supported. This method always return true. 1467 /// </summary> 1468 /// <param name="context">Descriptor context.</param> 1469 /// <returns>True.</returns> GetStandardValuesSupported(ITypeDescriptorContext context)1470 public override bool GetStandardValuesSupported(ITypeDescriptorContext context) 1471 { 1472 return true; 1473 } 1474 1475 /// <summary> 1476 /// Standard values are not exclusive. This method always return false. 1477 /// </summary> 1478 /// <param name="context">Descriptor context.</param> 1479 /// <returns>False.</returns> GetStandardValuesExclusive(ITypeDescriptorContext context)1480 public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) 1481 { 1482 return false; 1483 } 1484 1485 /// <summary> 1486 /// Get in the collection of standard values. 1487 /// </summary> 1488 /// <param name="context">Descriptor context.</param> GetStandardValues(ITypeDescriptorContext context)1489 public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) 1490 { 1491 ArrayList values = new ArrayList(); 1492 values.Add(Double.NaN); 1493 1494 return new StandardValuesCollection(values); 1495 } 1496 1497 /// <summary> 1498 /// Convert double.NaN to string "Not set" 1499 /// </summary> 1500 /// <param name="context">Descriptor context.</param> 1501 /// <param name="culture">Culture information.</param> 1502 /// <param name="value">Value to convert.</param> 1503 /// <param name="destinationType">Conversion destination type.</param> 1504 /// <returns>Converted object.</returns> ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)1505 public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) 1506 { 1507 double doubleValue = (double)value; 1508 if (destinationType == typeof(string)) 1509 { 1510 if(Double.IsNaN(doubleValue)) 1511 { 1512 return Constants.NotSetValue; 1513 } 1514 } 1515 1516 // Call base class 1517 return base.ConvertTo(context, culture, value, destinationType); 1518 } 1519 1520 /// <summary> 1521 /// Convert minimum or maximum values from string. 1522 /// </summary> ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)1523 public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) 1524 { 1525 // If converting from string value 1526 string crossingValue = value as string; 1527 if (crossingValue != null) 1528 { 1529 if (String.Compare(crossingValue, Constants.NotSetValue, StringComparison.OrdinalIgnoreCase) == 0) 1530 { 1531 return Double.NaN; 1532 } 1533 } 1534 1535 // Call base converter 1536 return base.ConvertFrom(context, culture, value); 1537 } 1538 1539 #endregion 1540 } 1541 1542 /// <summary> 1543 /// Designer converter class 1544 /// Converts Double.NaN values to/from "Not set". 1545 /// Converts value to/from date strings. 1546 /// </summary> 1547 internal class DoubleDateNanValueConverter : DoubleConverter 1548 { 1549 #region Converter methods 1550 1551 /// <summary> 1552 /// Standard values supported - return true 1553 /// </summary> 1554 /// <param name="context">Descriptor context.</param> 1555 /// <returns>Standard values supported.</returns> GetStandardValuesSupported(ITypeDescriptorContext context)1556 public override bool GetStandardValuesSupported(ITypeDescriptorContext context) 1557 { 1558 return true; 1559 } 1560 1561 /// <summary> 1562 /// Standard values are not exclusive - return false 1563 /// </summary> 1564 /// <param name="context">Descriptor context.</param> 1565 /// <returns>Non exclusive standard values.</returns> GetStandardValuesExclusive(ITypeDescriptorContext context)1566 public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) 1567 { 1568 return false; 1569 } 1570 1571 /// <summary> 1572 /// Fill in the list of predefined values. 1573 /// </summary> 1574 /// <param name="context">Descriptor context.</param> GetStandardValues(ITypeDescriptorContext context)1575 public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) 1576 { 1577 ArrayList values = new ArrayList(); 1578 values.Add(Double.NaN); 1579 1580 return new StandardValuesCollection(values); 1581 } 1582 1583 /// <summary> 1584 /// Convert values to string if step type is set to one of the DateTime type 1585 /// </summary> 1586 /// <param name="context">Descriptor context.</param> 1587 /// <param name="culture">Culture information.</param> 1588 /// <param name="value">Value to convert.</param> 1589 /// <param name="destinationType">Conversion destination type.</param> 1590 /// <returns>Converted object.</returns> ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)1591 public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) 1592 { 1593 // Check for NaN 1594 if (destinationType == typeof(string)) 1595 { 1596 if(Double.IsNaN((double)value)) 1597 { 1598 return Constants.NotSetValue; 1599 } 1600 } 1601 1602 if (context != null && context.Instance != null) 1603 { 1604 // Get access to the Axis object 1605 Axis axis = null; 1606 if(context.Instance is AxisScaleView) 1607 { 1608 axis = ((AxisScaleView)context.Instance).axis; 1609 } 1610 1611 #if Microsoft_CONTROL 1612 1613 else if(context.Instance is Cursor) 1614 { 1615 axis = ((Cursor)context.Instance).GetAxis(); 1616 } 1617 #endif // Microsoft_CONTROL 1618 1619 if (axis != null && destinationType == typeof(string)) 1620 { 1621 string strValue = ConvertDateTimeToString( 1622 (double)value, 1623 axis.GetAxisValuesType(), 1624 axis.InternalIntervalType); 1625 1626 if (strValue != null) 1627 return strValue; 1628 } 1629 1630 } 1631 return base.ConvertTo(context, culture, value, destinationType); 1632 } 1633 ConvertDateTimeToString( double dtValue, ChartValueType axisValuesType, DateTimeIntervalType dtIntervalType)1634 public static string ConvertDateTimeToString( 1635 double dtValue, 1636 ChartValueType axisValuesType, 1637 DateTimeIntervalType dtIntervalType) 1638 { 1639 string strValue = null; 1640 // Use axis values types if interval is automatic 1641 if (dtIntervalType == DateTimeIntervalType.Auto) 1642 { 1643 if (axisValuesType == ChartValueType.DateTime || 1644 axisValuesType == ChartValueType.Time || 1645 axisValuesType == ChartValueType.Date || 1646 axisValuesType == ChartValueType.DateTimeOffset) 1647 { 1648 strValue = DateTime.FromOADate(dtValue).ToString("g", System.Globalization.CultureInfo.CurrentCulture); 1649 } 1650 } 1651 else 1652 { 1653 if (dtIntervalType != DateTimeIntervalType.Number) 1654 { 1655 // Covert value to date/time 1656 if (dtIntervalType < DateTimeIntervalType.Hours) 1657 { 1658 strValue = DateTime.FromOADate(dtValue).ToShortDateString(); 1659 } 1660 else 1661 { 1662 strValue = DateTime.FromOADate(dtValue).ToString("g", System.Globalization.CultureInfo.CurrentCulture); 1663 } 1664 } 1665 } 1666 1667 if (axisValuesType == ChartValueType.DateTimeOffset && strValue != null) 1668 strValue += " +0"; 1669 1670 return strValue; 1671 } 1672 1673 /// <summary> 1674 /// Convert Min and Max values from string if step type is set to one of the DateTime type 1675 /// </summary> 1676 /// <param name="context">Descriptor context.</param> 1677 /// <param name="culture">Culture information.</param> 1678 /// <param name="value">Value to convert from.</param> 1679 /// <returns>Converted object.</returns> ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)1680 public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) 1681 { 1682 object result = null; 1683 bool convertFromDate = false; 1684 1685 // If converting from string value 1686 string crossingValue = value as string; 1687 if (crossingValue != null) 1688 { 1689 if (String.Compare(crossingValue, Constants.NotSetValue, StringComparison.OrdinalIgnoreCase) == 0) 1690 { 1691 return Double.NaN; 1692 } 1693 } 1694 1695 // If context interface provided check if we are dealing with DateTime values 1696 if (context != null && context.Instance != null && context.Instance is Axis) 1697 { 1698 1699 // Get axis object 1700 Axis axis = null; 1701 if(context.Instance is AxisScaleView) 1702 { 1703 axis = ((AxisScaleView)context.Instance).axis; 1704 } 1705 1706 #if Microsoft_CONTROL 1707 else if(context.Instance is Cursor) 1708 { 1709 axis = ((Cursor)context.Instance).GetAxis(); 1710 } 1711 #endif // Microsoft_CONTROL 1712 1713 if (axis != null && crossingValue != null) 1714 { 1715 if(axis.InternalIntervalType == DateTimeIntervalType.Auto) 1716 { 1717 if(axis.GetAxisValuesType() == ChartValueType.DateTime || 1718 axis.GetAxisValuesType() == ChartValueType.Date || 1719 axis.GetAxisValuesType() == ChartValueType.Time || 1720 axis.GetAxisValuesType() == ChartValueType.DateTimeOffset) 1721 { 1722 convertFromDate = true; 1723 } 1724 } 1725 else 1726 { 1727 if(axis.InternalIntervalType != DateTimeIntervalType.Number) 1728 { 1729 convertFromDate = true; 1730 } 1731 } 1732 } 1733 } 1734 1735 // Try to convert from double string 1736 try 1737 { 1738 result = base.ConvertFrom(context, culture, value); 1739 } 1740 catch (ArgumentException) 1741 { 1742 result = null; 1743 } 1744 catch (NotSupportedException) 1745 { 1746 result = null; 1747 } 1748 1749 // Try to convert from date/time string 1750 if (crossingValue != null && (convertFromDate || result == null)) 1751 { 1752 DateTime valueAsDate; 1753 bool parseSucceed = DateTime.TryParse(crossingValue, CultureInfo.InvariantCulture, DateTimeStyles.None, out valueAsDate); 1754 1755 if (parseSucceed) 1756 { 1757 return valueAsDate.ToOADate(); 1758 } 1759 } 1760 1761 // Call base converter 1762 return base.ConvertFrom(context, culture, value); 1763 } 1764 1765 #endregion 1766 } 1767 1768 } 1769 1770 1771