Option Strict On
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Windows.Forms.Control
Imports System.Threading
<Description("TrackerControl 2.0")> _
Public Class TrackerControl
Inherits System.Windows.Forms.Control
#Region "Private and public Declarations"
Private GraphThreadDelegate As New ThreadStart(AddressOf InternalThread)
Private GraphThread As New Thread(GraphThreadDelegate)
Private mover As Integer = 0
Private StopFlag As Boolean = False
Private _Avg As Integer = 0
Public Enum eTrackerRefresh
Enabled = 0
Disabled = 1
End Enum
Private _TrackerRefreshInDesignMode As eTrackerRefresh = eTrackerRefresh.Disabled
Private _TrackerRefreshInRuntimeMode As eTrackerRefresh = eTrackerRefresh.Enabled
Private _TrackerRefreshStartOnFirstValue As Boolean = False
Private _Value As Integer = 0
Private _Values As New List(Of Integer)
Private _ResetValueBuffer As Boolean = False
Private _Minimum As Integer = 0
Private _Maximum As Integer = 100
Private _InitialMaximum As Integer = 100
Private _StartValue As Integer = 0
Private _HighlightedRangeLowerBound As Integer = 25
Private _HighlightedRangeUpperBound As Integer = 75
Public Enum eRefreshingTime
ValueTriggered = -1
Custom = 0
Running = 20
Fast = 100
Medium = 500
Slow = 1000
End Enum
Private _RefreshInterval As eRefreshingTime = eRefreshingTime.Slow
Private _CustomRefreshInterval As Integer = eRefreshingTime.Slow
Private Const intDivision As Integer = 2
Private _ShowGridLines As eShowGridLines = eShowGridLines.Both
Public Enum eShowGridLines
Both = 0
Horizontal = 1
Vertical = 2
None = 3
End Enum
Private _GridSize As Integer = 12
Private _GridSizeForeColor As Color = Color.DarkGreen
Private _GridSizeBackColor As Color = Color.Black
Public Enum eGridMovement
MoveWithGraph = 0
Fixed = 1
End Enum
Private _GridMovement As eGridMovement = eGridMovement.MoveWithGraph
Private _ShowHighlightedRange As Boolean = False
Private _MinimumColor As Color = Color.Yellow
Private _MaximumColor As Color = Color.Red
Private _FillGraph As Boolean = False
Public Enum eGraphSizeMode
Fixed = 1
Zoom = 2
AutoAdjustMaximum = 3
End Enum
Private _GraphSizeMode As eGraphSizeMode = eGraphSizeMode.Fixed
Private _AvgBarShow As Boolean = False
Private _AvgBarMaximumColor As Color = Color.Yellow
Private _AvgBarMininumColor As Color = Color.Lime
Private _objLockValues As New Object
#End Region
#Region "Private Procedures"
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
' TrackerControl
Me.BackColor = System.Drawing.SystemColors.WindowText
Me.Text = "TrackerControl 2.0"
End Sub
''' <summary>
''' Internal thread for handling values and calculations
''' </summary>
''' <remarks></remarks>
Private Sub InternalThread()
' Loop until Stop is requested
Do While StopFlag = False
' Do nothing but also do not end thread, if refreshing is set to disabled.
If Me.DesignMode And Me._TrackerRefreshInDesignMode = eTrackerRefresh.Disabled Then
Thread.Sleep(_RefreshInterval)
Continue Do
ElseIf Not Me.DesignMode And Me._TrackerRefreshInRuntimeMode = eTrackerRefresh.Disabled Then
If Me._Values.Count > 0 And Not Me._TrackerRefreshStartOnFirstValue Then
Thread.Sleep(_RefreshInterval)
Continue Do
End If
End If
' Flush internal value buffer, if requested
If Me._ResetValueBuffer Then
SyncLock Me._objLockValues
Me._Values.Clear()
' Note that the job is done
Me._ResetValueBuffer = False
End SyncLock
' Skip processing this time
Continue Do
End If
If mover >= Me._GridSize - intDivision Then
mover = 0
Else
mover += intDivision
End If
If Me._GraphSizeMode = eGraphSizeMode.AutoAdjustMaximum Or Me._GraphSizeMode = eGraphSizeMode.Zoom Then
' AutoAdjustMaximum: Set Maximum to the highest available value.
' But make sure, that Maximum never falls below the initially set Maximum value (kind of lower bound for Maximum)
Dim CurMax As Integer = 0
For Each TmpValue As Integer In Me._Values
If TmpValue > CurMax Then
CurMax = TmpValue
End If
Next
If Me._GraphSizeMode = eGraphSizeMode.AutoAdjustMaximum Then
If CurMax > Me._InitialMaximum Then
Me._Maximum = CurMax
Else
Me._Maximum = Me._InitialMaximum
End If
If Me._Value > Me._Maximum Then
Me._Maximum = Me._Value
End If
ElseIf Me._GraphSizeMode = eGraphSizeMode.Zoom Then
' Zoom: Adjust Maximum, but never above the user set Maximum.
If CurMax > Me._Minimum + 1 Then
If CurMax < Me._InitialMaximum Then
Me._Maximum = CurMax
Else
Me._Maximum = Me._InitialMaximum
End If
Else
CurMax = Me._Minimum + 1
End If
End If
End If
SyncLock Me._objLockValues
If Me._Values.Count = 0 Then
Me._Values.Add(Me._StartValue)
ElseIf Me._Values.Count < (Me.Width) / intDivision Then
Me._Values.Add(_Value)
Else
Me._Values.RemoveAt(0)
Me._Values.Add(_Value)
End If
End SyncLock
' Calculate Average
If Me._AvgBarShow Then
Dim valuesum As Integer = 0
Dim NumberOfValuesForAvg As Integer
For i = 1 To Me._Values.Count - 1
valuesum += Me._Values(i)
Next
'NumberOfValuesForAvg = Convert.ToInt32(Me.Width / intDivision)
NumberOfValuesForAvg = Me._Values.Count
Me._Avg = Convert.ToInt32(valuesum / NumberOfValuesForAvg)
End If
' Provoke redrawing of control
If Not Me.StopFlag Then Me.Invalidate()
' Stick to the RefreshInterval
If Me._RefreshInterval = eRefreshingTime.Custom Then
Thread.Sleep(Me._CustomRefreshInterval)
Else
Thread.Sleep(_RefreshInterval)
End If
Loop
' Internal Thread is about to end -> flush value list
SyncLock Me._objLockValues
Me._Values.Clear()
End SyncLock
End Sub
''' <summary>
''' Recalculate a value using a given iFactor
''' </summary>
''' <param name="iFactor"></param>
''' <param name="Value"></param>
''' <returns></returns>
''' <remarks></remarks>
Private Function CnvValue(ByVal iFactor As Double, ByVal Value As Integer) As Integer
Dim Result As Integer
Result = Convert.ToInt32(Math.Round(iFactor * Convert.ToDouble(Value), 0, MidpointRounding.AwayFromZero))
Return Result
End Function
''' <summary>
''' Ascertain the gradient color for a given y-coordinate
''' </summary>
''' <param name="StartColor"></param>
''' <param name="EndColor"></param>
''' <param name="YCoord"></param>
''' <returns></returns>
''' <remarks></remarks>
Private Function GetGradientColorAccordingToYCoord(ByVal StartColor As Color, ByVal EndColor As Color, ByVal YCoord As Integer) As Color
Dim RGBResult As sRGBColorStructure
Dim StartRGB As sRGBColorStructure = GetRGBColorStructure(StartColor)
Dim EndRGB As sRGBColorStructure = GetRGBColorStructure(EndColor)
Dim TransitionSteps As Integer = Me.Height
Dim NormalizedValue As Integer = TransitionSteps - (YCoord)
If Me._GraphSizeMode = eGraphSizeMode.Zoom Then
If Me._Maximum < Me._InitialMaximum Then
NormalizedValue = Convert.ToInt32((Me._Maximum / Me._InitialMaximum) * NormalizedValue)
End If
End If
With RGBResult
.Red = StartRGB.Red + Convert.ToInt32(Math.Round((NormalizedValue * (EndRGB.Red - StartRGB.Red) / TransitionSteps), 0, MidpointRounding.ToEven))
.Green = StartRGB.Green + Convert.ToInt32(Math.Round((NormalizedValue * (EndRGB.Green - StartRGB.Green) / TransitionSteps), 0, MidpointRounding.ToEven))
.Blue = StartRGB.Blue + Convert.ToInt32(Math.Round((NormalizedValue * (EndRGB.Blue - StartRGB.Blue) / TransitionSteps), 0, MidpointRounding.ToEven))
End With
Return Color.FromArgb(RGBResult.Red, RGBResult.Green, RGBResult.Blue)
End Function
''' <summary>
''' Structure representing a RGB value triple
''' </summary>
''' <remarks></remarks>
Private Structure sRGBColorStructure
Dim Red As Integer
Dim Green As Integer
Dim Blue As Integer
End Structure
''' <summary>
''' Dissociation of a color into RGB values
''' </summary>
''' <param name="SystemColor"></param>
''' <returns></returns>
''' <remarks></remarks>
Private Function GetRGBColorStructure(ByVal SystemColor As Color) As sRGBColorStructure
Dim Result As sRGBColorStructure
Dim hexColor As String = SystemColor.ToArgb().ToString("X8").Substring(2, 6)
'Remove # if present
If hexColor.IndexOf("#") <> -1 Then
hexColor = hexColor.Replace("#", "")
End If
Dim red As Integer = 0
Dim green As Integer = 0
Dim blue As Integer = 0
If hexColor.Length = 6 Then
'#RRGGBB
red = Integer.Parse(hexColor.Substring(0, 2), Globalization.NumberStyles.AllowHexSpecifier)
green = Integer.Parse(hexColor.Substring(2, 2), Globalization.NumberStyles.AllowHexSpecifier)
blue = Integer.Parse(hexColor.Substring(4, 2), Globalization.NumberStyles.AllowHexSpecifier)
ElseIf hexColor.Length = 3 Then
'#RGB
red = Integer.Parse(hexColor(0).ToString() + hexColor(0).ToString(), Globalization.NumberStyles.AllowHexSpecifier)
green = Integer.Parse(hexColor(1).ToString() + hexColor(1).ToString(), Globalization.NumberStyles.AllowHexSpecifier)
blue = Integer.Parse(hexColor(2).ToString() + hexColor(2).ToString(), Globalization.NumberStyles.AllowHexSpecifier)
End If
With Result
.Red = red
.Green = green
.Blue = blue
End With
Return Result
End Function
#End Region
#Region "Public Properties"
Protected Overrides ReadOnly Property DefaultSize() As System.Drawing.Size
Get
Dim mSize As System.Drawing.Size = New System.Drawing.Size(200, 100)
Return mSize
End Get
End Property
<Category("Behavior"), _
DefaultValue(eRefreshingTime.Slow), _
Description("Sets the refreshing time of the TrackerControl.")> _
Public Property RefreshingTime() As eRefreshingTime
Get
Return Me._RefreshInterval
End Get
Set(ByVal Value As eRefreshingTime)
Me._RefreshInterval = Value
End Set
End Property
<Category("Behavior"), _
DefaultValue(eRefreshingTime.Slow), _
Description("Sets a custom refresh interval in milliseconds for the TrackerControl. RefreshingTime needs to be set to Custom to control this setting.")> _
Public Property CustomRefreshInterval() As Integer
Get
Return Me._CustomRefreshInterval
End Get
Set(ByVal Value As Integer)
If Value < eRefreshingTime.Slow Then
Me._CustomRefreshInterval = eRefreshingTime.Slow
Else
Me._CustomRefreshInterval = Value
End If
End Set
End Property
<Category("Behavior"), _
DefaultValue(eTrackerRefresh.Disabled), _
Description("Enable or disable refreshing of the TrackerControl in design mode.")> _
Public Property TrackerRefreshInDesignMode() As eTrackerRefresh
Get
Return Me._TrackerRefreshInDesignMode
End Get
Set(ByVal value As eTrackerRefresh)
Me._TrackerRefreshInDesignMode = value
End Set
End Property
<Category("Behavior"), _
DefaultValue(eTrackerRefresh.Enabled), _
Description("Enable or disable refreshing of the TrackerControl in runtime mode.")> _
Public Property TrackerRefreshInRuntimeMode() As eTrackerRefresh
Get
Return Me._TrackerRefreshInRuntimeMode
End Get
Set(ByVal value As eTrackerRefresh)
Me._TrackerRefreshInRuntimeMode = value
End Set
End Property
<Category("Behavior"), _
DefaultValue(False), _
Description("Enable refreshing of the TrackerControl on first value, even if TrackerRefreshInRuntimeMode is set to Disabled.")> _
Public Property TrackerRefreshStartOnFirstValue() As Boolean
Get
Return Me._TrackerRefreshStartOnFirstValue
End Get
Set(ByVal value As Boolean)
Me._TrackerRefreshStartOnFirstValue = value
End Set
End Property
<Category("Behavior"), _
DefaultValue(eShowGridLines.Both), _
Description("Show grid lines in the background of the TrackerControl.")> _
Public Property ShowGridLines() As eShowGridLines
Get
Return Me._ShowGridLines
End Get
Set(ByVal value As eShowGridLines)
Me._ShowGridLines = value
End Set
End Property
<Category("Behavior"), _
DefaultValue(12), _
Description("The grid size (mesh) in pixels of the TrackerControl.")> _
Public Property GridSize() As Integer
Get
Return Me._GridSize
End Get
Set(ByVal Value As Integer)
If Value > 0 Then Me._GridSize = Value
End Set
End Property
<Category("Behavior"), _
DefaultValue(GetType(Color), "Color.DarkGreen"), _
Description("Color of the grid lines of the TrackerControl.")> _
Public Property GridForeColor() As Color
Get
Return Me._GridSizeForeColor
End Get
Set(ByVal value As Color)
Me._GridSizeForeColor = value
End Set
End Property
<Category("Behavior"), _
DefaultValue(GetType(Color), "Color.Black"), _
Description("Background color of the TrackerControl.")> _
Public Property GridBackColor() As Color
Get
Return Me._GridSizeBackColor
End Get
Set(ByVal value As Color)
Me._GridSizeBackColor = value
End Set
End Property
<Category("Behavior"), _
DefaultValue(eGridMovement.MoveWithGraph), _
Description("Move the grid with the graph when refreshing or fix it to background of the TrackerControl.")> _
Public Property GridMovement() As eGridMovement
Get
Return Me._GridMovement
End Get
Set(ByVal value As eGridMovement)
Me._GridMovement = value
End Set
End Property
<Category("Behavior"), _
DefaultValue(50), _
Description("The current value of the TrackerControl. If GraphSizeMode is set to AutoAdjustMaximum any value >= Minimum is accepted. Otherwise only values in the range specified by the Minimum and Maximum settings are allowed.")> _
Public Property Value() As Integer
Get
Return Me._Value
End Get
Set(ByVal Value As Integer)
If Me._GraphSizeMode = eGraphSizeMode.AutoAdjustMaximum Then
If Me._Value >= Me._Minimum Then
Me._Value = Value
Else
Me._Value = Me._Minimum
End If
Else
If Value > Me._Maximum Then
'_Value = me._Maximum
Me._Maximum = Value
Me._Value = Value
ElseIf Value < Me._Minimum Then
Me._Value = Me._Minimum
Else
Me._Value = Value
End If
End If
End Set
End Property
<Category("Behavior"), _
DefaultValue(0), _
Description("The lower bound of the range the TrackerControl is working with.")> _
Public Property Minimum() As Integer
Get
Return Me._Minimum
End Get
Set(ByVal value As Integer)
If value > Me._HighlightedRangeLowerBound Then
Me._Minimum = Me._HighlightedRangeLowerBound
Else
Me._Minimum = value
End If
Me.Invalidate()
End Set
End Property
<Category("Behavior"), _
DefaultValue(100), _
Description("The upper bound of the range this Tracker is working with. When GraphSizeMode is set to AutoAdjustMaximum this value is adjusted dynamically.")> _
Public Property Maximum() As Integer
Get
Return Me._Maximum
End Get
Set(ByVal value As Integer)
If value < Me._HighlightedRangeUpperBound And Me._ShowHighlightedRange Then
Me._Maximum = Me._HighlightedRangeUpperBound
Else
Me._Maximum = value
End If
Me._InitialMaximum = Me._Maximum
Me.Invalidate()
End Set
End Property
<Category("Behavior"), _
DefaultValue(0), _
Description("Sets the start value of the TrackerControl, within the range specified by the Minimum and Maximum settings.")> _
Public Property StartValue() As Integer
Get
Return Me._StartValue
End Get
Set(ByVal Value As Integer)
If Me._GraphSizeMode = eGraphSizeMode.AutoAdjustMaximum Then
Me._StartValue = Value
Else
If Value > Me._Maximum Then
'_Value = me._Maximum
Me._Maximum = Value
Me._StartValue = Value
ElseIf Value < Me._Minimum Then
Me._StartValue = Me._Minimum
Else
Me._StartValue = Value
End If
End If
End Set
End Property
<Category("Behavior"), _
DefaultValue(75), _
Description("The upper bound of the highlighted range.")> _
Public Property HighlightedRangeUpperBound() As Integer
Get
Return Me._HighlightedRangeUpperBound
End Get
Set(ByVal value As Integer)
If value > Me._Maximum Then
Me._HighlightedRangeUpperBound = Me._Maximum
ElseIf value < Me._HighlightedRangeLowerBound Then
Me._HighlightedRangeUpperBound = Me._HighlightedRangeLowerBound
Else
Me._HighlightedRangeUpperBound = value
End If
Me.Invalidate()
End Set
End Property
<Category("Behavior"), _
DefaultValue(25), _
Description("The lower bound of the highlighted range.")> _
Public Property HighlightedRangeLowerBound() As Integer
Get
Return Me._HighlightedRangeLowerBound
End Get
Set(ByVal value As Integer)
If value > Me._HighlightedRangeUpperBound Then
Me._HighlightedRangeLowerBound = Me._HighlightedRangeUpperBound
ElseIf value < Me._Minimum Then
Me._HighlightedRangeLowerBound = Me._Minimum
Else
Me._HighlightedRangeLowerBound = value
End If
Me.Invalidate()
End Set
End Property
<Category("Behavior"), _
DefaultValue(False), _
Description("Highlight the area between HighlightedRangeLowerBound and HighlightedRangeUpperBound. Only applies when GraphSizeMode is set to Fixed.")> _
Public Property ShowHighlightedRange() As Boolean
Get
Return Me._ShowHighlightedRange
End Get
Set(ByVal value As Boolean)
Me._ShowHighlightedRange = value
End Set
End Property
<Category("Behavior"), _
DefaultValue(GetType(Color), "Color.Yellow"), _
Description("The lower gradient color (minimum color).")> _
Public Property MinimumColor() As Color
Get
Return Me._MinimumColor
End Get
Set(ByVal value As Color)
Me._MinimumColor = value
End Set
End Property
<Category("Behavior"), _
DefaultValue(GetType(Color), "Color.Red"), _
Description("The upper gradient color (maximum color).")> _
Public Property MaximumColor() As Color
Get
Return Me._MaximumColor
End Get
Set(ByVal value As Color)
Me._MaximumColor = value
End Set
End Property
<Category("Behavior"), _
DefaultValue(False), _
Description("Colorize area underneath garph using the appropriate gradient.")> _
Public Property FillGraph() As Boolean
Get
Return Me._FillGraph
End Get
Set(ByVal value As Boolean)
Me._FillGraph = value
End Set
End Property
<Category("Behavior"), _
DefaultValue(eGraphSizeMode.Fixed), _
Description("Sizing of drawn graph. If set to Zoom and vertical grid lines are shown, number of and distance between the vertical grid lines are adjusted dynamically.")> _
Public Property GraphSizeMode() As eGraphSizeMode
Get
Return Me._GraphSizeMode
End Get
Set(ByVal value As eGraphSizeMode)
Me._GraphSizeMode = value
End Set
End Property
<Category("Behavior"), _
DefaultValue(False), _
Description("Show calculated average of displayed values as a horizontal bar.")> _
Public Property AvgBarShow() As Boolean
Get
Return Me._AvgBarShow
End Get
Set(ByVal value As Boolean)
Me._AvgBarShow = value
End Set
End Property
<Category("Behavior"), _
DefaultValue(GetType(Color), "Color.Lime"), _
Description("The avg bar minimum gradient color.")> _
Public Property AvgBarMinimumColor() As Color
Get
Return Me._AvgBarMininumColor
End Get
Set(ByVal value As Color)
Me._AvgBarMininumColor = value
End Set
End Property
<Category("Behavior"), _
DefaultValue(GetType(Color), "Color.Yellow"), _
Description("The avg bar maximum gradient color.")> _
Public Property AvgBarMaximumColor() As Color
Get
Return Me._AvgBarMaximumColor
End Get
Set(ByVal value As Color)
Me._AvgBarMaximumColor = value
End Set
End Property
#End Region
#Region "Public Procedures"
Public Sub New()
MyBase.New()
InitializeComponent()
SetStyle(ControlStyles.ResizeRedraw, True)
SetStyle(ControlStyles.UserPaint, True)
SetStyle(ControlStyles.AllPaintingInWmPaint, True)
SetStyle(ControlStyles.DoubleBuffer, True)
GraphThread.Start()
End Sub
''' <summary>
''' Stop internal thread
''' </summary>
''' <param name="disposing"></param>
''' <remarks></remarks>
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
' Set stop flag for internal thread
StopFlag = True
MyBase.Dispose(disposing)
End Sub
''' <summary>
''' Primary graph drawing procedure
''' </summary>
''' <param name="e"></param>
''' <remarks></remarks>
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)
Dim i As Integer
' Draw grid lines according to control settings
If Me._ShowGridLines = eShowGridLines.Both Or Me._ShowGridLines = eShowGridLines.Horizontal Then
If Me._GraphSizeMode = eGraphSizeMode.Zoom Then
For i = 1 To CInt(Me.Height / (Me._GridSize * (1 / (Me._Maximum / Me._InitialMaximum))))
e.Graphics.DrawLine(New Pen(Me._GridSizeForeColor), 0, Convert.ToInt32(i * (Me._GridSize * (1 / (Me._Maximum / Me._InitialMaximum)))), Me.Width, Convert.ToInt32(i * (Me._GridSize * (1 / (Me._Maximum / Me._InitialMaximum)))))
Next i
Else
For i = 1 To CInt(Me.Height / Me._GridSize)
e.Graphics.DrawLine(New Pen(Me._GridSizeForeColor), 0, i * Me._GridSize, Me.Width, i * Me._GridSize)
Next i
End If
End If
If Me._ShowGridLines = eShowGridLines.Both Or Me._ShowGridLines = eShowGridLines.Vertical Then
For i = 1 To CInt(Me.Width / Me._GridSize)
If Me._GridMovement = eGridMovement.MoveWithGraph Then
e.Graphics.DrawLine(New Pen(Me._GridSizeForeColor), i * Me._GridSize - mover, 0, i * Me._GridSize - mover, Me.Height)
Else
e.Graphics.DrawLine(New Pen(Me._GridSizeForeColor), i * Me._GridSize, 0, i * Me._GridSize, Me.Height)
End If
Next i
End If
Dim iMaximum As Integer
Dim iMinimum As Integer
Dim iFactor As Double
' Recalculate Minimum und Maximum to iMinimum and iMaximum: Normalize to pixel height of control
If Me._Maximum < Me.Height Then
iMaximum = Me.Height
iFactor = Convert.ToDouble(Me.Height) / Convert.ToDouble(_Maximum)
Else
iMaximum = Me._Maximum
iFactor = 1
End If
If Me._Minimum > 0 Then
iMinimum = Convert.ToInt32(Math.Round(iFactor * Convert.ToDouble(_Minimum), 0, MidpointRounding.AwayFromZero))
Else
iMinimum = 0
End If
' Define brush and pen for later use
Dim localBrush As Drawing2D.LinearGradientBrush = Nothing
Dim localPen As Pen = Nothing
' Draw graph (coherent lines) and fill area underneath if applicable
For i = 1 To Me._Values.Count - 1
' Normalize value tuple for current line
Dim StartValue As Integer = CnvValue(iFactor, Convert.ToInt32(_Values(i)))
Dim EndValue As Integer = CnvValue(iFactor, Convert.ToInt32(_Values(i - 1)))
' Translate value tuple to actual coordinates within control
Dim StartPoint As New Point(Me.Width - intDivision * (_Values.Count - i), CInt(Me.Height * (iMaximum - CnvValue(iFactor, Convert.ToInt32(_Values(i)))) / (iMaximum - iMinimum)))
Dim EndPoint As New Point(Me.Width - intDivision * (_Values.Count - i + 1), CInt(Me.Height * (iMaximum - CnvValue(iFactor, Convert.ToInt32(_Values(i - 1)))) / (iMaximum - iMinimum)))
' Determine start and end color of current line
Dim StartColor As Color = GetGradientColorAccordingToYCoord(Me._MinimumColor, Me._MaximumColor, StartPoint.Y)
Dim EndColor As Color = GetGradientColorAccordingToYCoord(Me._MinimumColor, Me._MaximumColor, EndPoint.Y)
If Not localBrush Is Nothing Then localBrush.Dispose()
localBrush = New Drawing2D.LinearGradientBrush(StartPoint, EndPoint, StartColor, EndColor)
localBrush.WrapMode = Drawing2D.WrapMode.TileFlipX
localBrush.GammaCorrection = True
If localPen Is Nothing Then
localPen = New Pen(localBrush, 1)
Else
localPen.Brush = localBrush
localPen.Width = 1
End If
localPen.StartCap = Drawing2D.LineCap.Round
localPen.EndCap = Drawing2D.LineCap.Round
' Draw the line
e.Graphics.DrawLine(localPen, StartPoint, EndPoint)
' If applicable, fill the area underneath the line
If Me._FillGraph Then
Do Until StartValue = iMinimum And EndValue = iMinimum
StartValue -= 1
EndValue -= 1
If StartValue < iMinimum Then StartValue = iMinimum
If EndValue < iMinimum Then EndValue = iMinimum
StartPoint = New Point(Me.Width - intDivision * (_Values.Count - i), CInt(Me.Height * (iMaximum - StartValue) / (iMaximum - iMinimum)))
EndPoint = New Point(Me.Width - intDivision * (_Values.Count - i + 1), CInt(Me.Height * (iMaximum - EndValue) / (iMaximum - iMinimum)))
StartColor = GetGradientColorAccordingToYCoord(Me._MinimumColor, Me._MaximumColor, StartPoint.Y)
EndColor = GetGradientColorAccordingToYCoord(Me._MinimumColor, Me._MaximumColor, EndPoint.Y)
localBrush.Dispose()
localBrush = New Drawing2D.LinearGradientBrush(StartPoint, EndPoint, StartColor, EndColor)
localBrush.WrapMode = Drawing2D.WrapMode.TileFlipX
localBrush.GammaCorrection = True
localPen.Brush = localBrush
localPen.Width = 1
e.Graphics.DrawLine(localPen, StartPoint, EndPoint)
Loop
End If
Next i
' Show average value as horizontal bar
If Me._AvgBarShow Then
Dim x1 As Integer = 0
Dim y1 As Integer = Convert.ToInt32(Me.Height * (iMaximum - CnvValue(iFactor, Convert.ToInt32(Me._Avg))) / (iMaximum - iMinimum))
Dim x2 As Integer = Me.Width
Dim y2 As Integer = Convert.ToInt32(Me.Height * (iMaximum - CnvValue(iFactor, Convert.ToInt32(Me._Avg))) / (iMaximum - iMinimum))
Dim BarColor As Color = GetGradientColorAccordingToYCoord(Me._AvgBarMininumColor, Me._AvgBarMaximumColor, y1)
e.Graphics.DrawLine(New Pen(BarColor), x1, y1, x2, y2)
End If
ControlPaint.DrawBorder3D(e.Graphics, 0, 0, Width, Height, Border3DStyle.Sunken)
End Sub
''' <summary>
''' Setting the background color and the highlighted range, if applicable
''' </summary>
''' <param name="pevent"></param>
''' <remarks></remarks>
Protected Overrides Sub OnPaintBackground(ByVal pevent As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaintBackground(pevent)
Me.BackColor = Me._GridSizeBackColor
If Me._ShowHighlightedRange And Not Me._GraphSizeMode = eGraphSizeMode.Zoom And Not Me._GraphSizeMode = eGraphSizeMode.AutoAdjustMaximum Then
' Benannten Bereich hervorheben
Dim myColor As Color
myColor = Color.FromArgb(64, Color.White)
Dim myBrush As New SolidBrush(myColor)
Dim range As New Rectangle(0, CInt((Me.Maximum - Me._HighlightedRangeUpperBound) / (Me.Maximum - Me.Minimum) * Me.Height), Me.Width, CInt((Me._HighlightedRangeUpperBound - Me._HighlightedRangeLowerBound) / (Me.Maximum - Me.Minimum) * Me.Height))
pevent.Graphics.FillRectangle(myBrush, range)
End If
End Sub
''' <summary>
''' Adjust internal value buffer on resize
''' </summary>
''' <param name="e"></param>
''' <remarks></remarks>
Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
MyBase.OnResize(e)
' If size decreases during runtime, downsize the internal value buffer accordingly
If Me._Values.Count > (Me.Width) / intDivision Then
SyncLock Me._objLockValues
Me._Values.RemoveRange(0, Me._Values.Count - CInt((Me.Width) / intDivision))
End SyncLock
End If
End Sub
''' <summary>
''' Flush all values and clear graph
''' </summary>
''' <param name="WaitForCompletion">If set to True, the call waits until the job is done.</param>
''' <remarks></remarks>
Public Sub ResetValueBuffer(Optional ByVal WaitForCompletion As Boolean = False)
SyncLock Me._objLockValues
Me._ResetValueBuffer = True
End SyncLock
If WaitForCompletion Then
Do Until Me._ResetValueBuffer = False
Thread.Sleep(10)
Loop
End If
End Sub
#End Region
End Class