All too often I see examples of custom controls which unnecessarily add child controls. For instance, a custom trackbar control may have a label or panel added to act as the scrolling thumb tab.
In this instance that's not so bad as it only creates one extra window handle, but where several such child controls are added the user will see what is percieved as flicker as each window is individually painted one after the other. No amount of doublebuffering will cure this.
Since we need to respond to mouse, keyboard or code change events and then calculate the exact bounds of the child control, it really makes no sense to add the extra control. We may as well apply those bounds to a rectangle instead, and then paint within this rectangle (don't have to paint a Rectangle just need to paint inside it).
The following example shows how to define and use a rectangle for this purpose. I have tried to make it behave just like a standard System.Windows.Forms.Trackbar control, but have made no offort to have it look like one. Hopefully, you'll be able to apply the same principles to other custom controls, perhaps using some of the many control renderers to simulate "lite" controls.
by: Mick Dohertys'
In this instance that's not so bad as it only creates one extra window handle, but where several such child controls are added the user will see what is percieved as flicker as each window is individually painted one after the other. No amount of doublebuffering will cure this.
Since we need to respond to mouse, keyboard or code change events and then calculate the exact bounds of the child control, it really makes no sense to add the extra control. We may as well apply those bounds to a rectangle instead, and then paint within this rectangle (don't have to paint a Rectangle just need to paint inside it).
The following example shows how to define and use a rectangle for this purpose. I have tried to make it behave just like a standard System.Windows.Forms.Trackbar control, but have made no offort to have it look like one. Hopefully, you'll be able to apply the same principles to other custom controls, perhaps using some of the many control renderers to simulate "lite" controls.
VB net Sample:
Imports System.ComponentModel
Namespace Dotnetrix.Samples.VB
<DefaultEvent("Scroll"), _
DefaultProperty("Value"), _
ToolboxBitmap(GetType(System.Windows.Forms.TrackBar))> _
Public Class TrackBar
Inherits Control
Public Sub New()
MyBase.New()
Me.SetStyle(ControlStyles.SupportsTransparentBackColor Or ControlStyles.OptimizedDoubleBuffer Or _
ControlStyles.AllPaintingInWmPaint Or ControlStyles.Selectable Or ControlStyles.UserMouse, True)
Me.Thumb = New Rectangle()
Me.LayoutTrackBarParts()
End Sub
Protected Overrides ReadOnly Property DefaultSize() As System.Drawing.Size
Get
Return New Size(100, 60)
End Get
End Property
#Region " Event Delarations "
Public Event Scroll As EventHandler
Public Event ValueChanged As EventHandler
#End Region
#Region " Private Instance Variables "
Private _orientation As Orientation = Orientation.Horizontal
Private _minimum As Int32
Private _maximum As Int32 = 10
Private _smallChange As Int32 = 1
Private _largeChange As Int32 = 5
Private _value As Int32
Private _tickStyle As TickStyle = TickStyle.BottomRight
Private _tickFrequency As Int32 = 1
Private _thumbDragging As Boolean
Private _scrollUp As Boolean
Private Thumb As Rectangle
Private _thumbFocused As Boolean
Private scrollTimer As Timer
#End Region
#Region " Public properties "
<DefaultValue(GetType(Orientation), "Horizontal")> _
Public Property Orientation() As Orientation
Get
Return _orientation
End Get
Set(ByVal value As Orientation)
If (_orientation <> value) Then
_orientation = value
Dim w, h As Int32
w = Me.Height
h = Me.Width
Me.Size = New Size(w, h)
Me.LayoutTrackBarParts()
Me.Invalidate()
End If
End Set
End Property
<DefaultValue(0), _
RefreshProperties(RefreshProperties.All)> _
Public Property Minimum() As Int32
Get
Return _minimum
End Get
Set(ByVal value As Int32)
If (_minimum <> value) Then
_minimum = value
If (_maximum <= value) Then
_maximum = value
End If
Me.LayoutTrackBarParts()
Me.Invalidate()
End If
End Set
End Property
<DefaultValue(10)> _
Public Property Maximum() As Int32
Get
Return _maximum
End Get
Set(ByVal value As Int32)
If (_maximum <> value) Then
_maximum = value
If (Minimum >= value) Then
Minimum = value
End If
Me.LayoutTrackBarParts()
Me.Invalidate()
End If
End Set
End Property
<DefaultValue(1)> _
Public Property SmallChange() As Int32
Get
Return _smallChange
End Get
Set(ByVal value As Int32)
_smallChange = value
End Set
End Property
<DefaultValue(5)> _
Public Property LargeChange() As Int32
Get
Return _largeChange
End Get
Set(ByVal value As Int32)
_largeChange = value
End Set
End Property
Public Property Value() As Int32
Get
If (_value < Me.Minimum) Then
Return Me.Minimum
End If
Return _value
End Get
Set(ByVal value As Int32)
If (value < Me.Minimum) Then
value = _minimum
End If
If (value > _maximum) Then
value = _maximum
End If
If (value <> _value) Then
_value = value
Me.LayoutTrackBarParts()
Me.OnValueChanged(EventArgs.Empty)
End If
End Set
End Property
Private Function ShouldSerializeValue() As Boolean
Return Me._value <> Me.Minimum
End Function
Private Sub ResetValue()
Me._value = Me.Minimum
End Sub
<DefaultValue(False)> _
Public Shadows Property TabStop() As Boolean
Get
Return MyBase.TabStop
End Get
Set(ByVal value As Boolean)
MyBase.TabStop = value
End Set
End Property
<DefaultValue(""), _
Browsable(False), _
EditorBrowsable(EditorBrowsableState.Never)> _
Public Overrides Property Text() As String
Get
Return String.Empty
End Get
Set(ByVal value As String)
MyBase.Text = String.Empty
End Set
End Property
<DefaultValue(GetType(TickStyle), "BottomRight")> _
Public Property TickStyle() As TickStyle
Get
Return _tickStyle
End Get
Set(ByVal value As TickStyle)
If (_tickStyle <> value) Then
_tickStyle = value
Me.Invalidate()
End If
End Set
End Property
<DefaultValue(1)> _
Public Property TickFrequency() As Int32
Get
Return _tickFrequency
End Get
Set(ByVal value As Int32)
If (_tickFrequency <> value) Then
_tickFrequency = value
Me.Invalidate()
End If
End Set
End Property
#End Region
#Region " private Properties "
Private ReadOnly Property Horizontal() As Boolean
Get
Return _orientation = Orientation.Horizontal
End Get
End Property
Private Property ThumbDragging() As Boolean
Get
Return _thumbDragging
End Get
Set(ByVal value As Boolean)
If (_thumbDragging <> value) Then
_thumbDragging = value
Me.Invalidate()
End If
End Set
End Property
#End Region
#Region " Overridden Methods "
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
'Do default painting
MyBase.OnPaint(e)
'Draw Tick Marks
DrawTicks(e.Graphics)
'Draw Channel
Dim channelBounds As Rectangle
If Me.Horizontal Then
channelBounds = New Rectangle(6, Me.Height / 2 - 2, Me.Width - 16, 4)
Else
channelBounds = New Rectangle(Me.Width / 2 - 2, 6, 4, Me.Height - 16)
End If
ControlPaint.DrawBorder3D(e.Graphics, channelBounds, Border3DStyle.Sunken)
' Draw the Thumb Object
Using brush As SolidBrush = New SolidBrush(Color.Blue)
If (_thumbFocused) Then
brush.Color = Color.Green
End If
If (ThumbDragging) Then
brush.Color = Color.Red
End If
e.Graphics.FillRectangle(brush, Me.Thumb)
End Using
'Draw Focus
If (Me.Focused AndAlso Me.ShowFocusCues) Then
ControlPaint.DrawFocusRectangle(e.Graphics, Me.ClientRectangle)
End If
End Sub
Protected Overrides Sub OnGotFocus(ByVal e As EventArgs)
MyBase.OnGotFocus(e)
_thumbFocused = (Me.Focused AndAlso Me.ShowFocusCues)
Me.Invalidate()
End Sub
Protected Overrides Sub OnLostFocus(ByVal e As EventArgs)
MyBase.OnLostFocus(e)
_thumbFocused = (Me.Focused AndAlso Me.ShowFocusCues)
Me.Invalidate()
End Sub
Protected Overrides Function IsInputKey(ByVal keyData As Keys) As Boolean
Select Case (keyData)
Case Keys.Up, Keys.Down, Keys.Left, Keys.Right
Return True
Case Else
Return MyBase.IsInputKey(keyData)
End Select
End Function
Protected Overrides Sub OnKeyDown(ByVal e As KeyEventArgs)
MyBase.OnKeyDown(e)
Select Case (e.KeyCode)
Case Keys.Up, Keys.Left
If (Me.Horizontal) Then
Me.Value -= _smallChange
Else
Me.Value += _smallChange
End If
Case Keys.Down, Keys.Right
If (Me.Horizontal) Then
Me.Value += _smallChange
Else
Me.Value -= _smallChange
End If
Case Keys.PageDown
If (Me.Horizontal) Then
Me.Value += _largeChange
Else
Me.Value -= _largeChange
End If
Case Keys.PageUp
If (Me.Horizontal) Then
Me.Value -= _largeChange
Else
Me.Value += _largeChange
End If
Case Keys.Home
If (Me.Horizontal) Then
Me.Value = _minimum
Else
Me.Value = _maximum
End If
Case Keys.End
If (Me.Horizontal) Then
Me.Value = _maximum
Else
Me.Value = _minimum
End If
End Select
End Sub
Protected Overrides Sub OnMouseWheel(ByVal e As MouseEventArgs)
MyBase.OnMouseWheel(e)
Me.Value += (e.Delta / WHEEL_DELTA) * WHEEL_LINES
End Sub
Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
MyBase.OnMouseDown(e)
If (e.Button = MouseButtons.Left) Then
ThumbDragging = Thumb.Contains(e.Location)
If (Not ThumbDragging) Then
If (Me.Horizontal) Then
_scrollUp = e.X > Thumb.Right
Else
_scrollUp = e.Y < Thumb.Top
End If
If (scrollTimer Is Nothing) Then
InitTimer()
End If
scrollTimer.Start()
End If
End If
End Sub
Protected Overrides Sub OnMouseUp(ByVal e As MouseEventArgs)
MyBase.OnMouseUp(e)
ThumbDragging = False
If (Me.scrollTimer IsNot Nothing) Then
Me.scrollTimer.Stop()
End If
End Sub
Protected Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)
MyBase.OnMouseMove(e)
If (ThumbDragging) Then
Me.Value = ValueFromPoint(e.Location)
End If
End Sub
Protected Overrides Sub OnVisibleChanged(ByVal e As EventArgs)
MyBase.OnVisibleChanged(e)
If (Me.Visible) Then
Me.LayoutTrackBarParts()
End If
End Sub
Protected Overrides Sub OnSizeChanged(ByVal e As EventArgs)
MyBase.OnSizeChanged(e)
Me.LayoutTrackBarParts()
End Sub
#End Region
#Region " Protected Methods "
Protected Overridable Sub OnScroll(ByVal e As EventArgs)
RaiseEvent Scroll(Me, e)
End Sub
Protected Overridable Sub OnValueChanged(ByVal eventArgs As EventArgs)
RaiseEvent ValueChanged(Me, eventArgs)
Me.LayoutTrackBarParts()
Me.OnScroll(eventArgs)
Me.Invalidate()
End Sub
#End Region
#Region " Internal Methods "
Private Sub LayoutTrackBarParts()
If Me.Horizontal Then
Thumb.Size = New Size(14, 28)
Else
Thumb.Size = New Size(28, 14)
End If
Dim channelLength As Single
If Me.Horizontal Then
channelLength = Me.Width - 26 ' Channel Left margin + Channel Right margin + Thumb.Width
Else
channelLength = Me.Height - 26 ' Channel Top margin + Channel Bottom margin + Thumb.Height
End If
Dim stepCount As Single = (Me.Maximum - Me.Minimum)
Dim stepSize As Single
If stepCount > 0 Then
stepSize = channelLength / stepCount
Else
stepSize = 0
End If
Dim thumbOffset As Single = (stepSize) * (Me.Value - Me.Minimum)
If Me.Horizontal Then
Thumb.Location = Point.Round(New PointF(6 + thumbOffset, Me.Height / 2 - 14))
Else
Thumb.Location = Point.Round(New PointF(Me.Width / 2 - 14, channelLength - thumbOffset + 6))
End If
End Sub
Private Sub InitTimer()
Me.scrollTimer = New Timer()
Me.scrollTimer.Interval = 500
AddHandler scrollTimer.Tick, AddressOf scrollTimer_Tick
End Sub
Private Sub scrollTimer_Tick(ByVal sender As Object, ByVal e As EventArgs)
If (_scrollUp) Then
Me.Value += Me.LargeChange
Else
Me.Value -= Me.LargeChange
End If
If (Me._value = Me.Minimum OrElse Me._value = Me.Maximum) Then
Me.scrollTimer.Stop()
End If
Dim val As Int32 = Me.ValueFromPoint(Me.PointToClient(Cursor.Position))
If (_scrollUp AndAlso Me._value > val) Then
Me.scrollTimer.Stop()
End If
If (Not _scrollUp AndAlso Me._value < val) Then
Me.scrollTimer.Stop()
End If
End Sub
Private Function ValueFromPoint(ByVal point As Point) As Int32
Dim channelLength As Single
If (Me.Horizontal) Then
channelLength = Me.Width - 26 ' Channel Left margin + Channel Right margin + Thumb.Width
Else
channelLength = Me.Height - 26 ' Channel Top margin + Channel Bottom margin + Thumb.Height
End If
Dim stepCount As Single = (Me.Maximum - Me.Minimum)
Dim stepSize As Single = 0
If (stepCount > 0) Then
stepSize = channelLength / stepCount
End If
If (Me.Horizontal) Then
point.Offset(-7, 0)
Return (point.X / stepSize) + Me.Minimum
End If
point.Offset(0, -7)
Return Me.Maximum - (point.Y / stepSize) + Me.Minimum
End Function
Private Sub DrawTicks(ByVal graphics As Graphics)
If (TickStyle <> TickStyle.None) Then
'TODO: Implement Tick Drawing
End If
End Sub
#End Region
Private WHEEL_DELTA As Int32 = SystemInformation.MouseWheelScrollDelta
Private WHEEL_LINES As Int32 = SystemInformation.MouseWheelScrollLines
End Class
End Namespace
CSharp Sample:
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
using System;
namespace Dotnetrix.Samples.CSharp
{
[DefaultEvent("Scroll")]
[DefaultProperty("Value")]
[ToolboxBitmap(typeof(System.Windows.Forms.TrackBar))]
public class TrackBar : Control
{
public TrackBar()
: base()
{
this.SetStyle(ControlStyles.SupportsTransparentBackColor | ControlStyles.OptimizedDoubleBuffer |
ControlStyles.AllPaintingInWmPaint | ControlStyles.Selectable | ControlStyles.UserMouse, true);
this.Thumb = new Rectangle();
this.LayoutTrackBarParts();
}
protected override Size DefaultSize
{
get
{
return new Size(100, 60);
}
}
#region Event Delarations
public event EventHandler Scroll;
public event EventHandler ValueChanged;
#endregion
#region Private Instance Variables
private Orientation orientation = Orientation.Horizontal;
private int minimum = 0;
private int maximum = 10;
private int smallChange = 1;
private int largeChange = 5;
private int _value = 0;
private TickStyle tickStyle = TickStyle.BottomRight;
private int tickFrequency = 1;
private bool thumbDragging = false;
private bool scrollUp = false;
private Rectangle Thumb;
private bool ThumbFocused;
private Timer scrollTimer;
#endregion
#region Public properties
[DefaultValue(typeof(Orientation), "Horizontal")]
public Orientation Orientation
{
get { return this.orientation; }
set
{
if (this.orientation != value)
{
this.orientation = value;
int w, h;
w = this.Height;
h = this.Width;
this.Size = new Size(w, h);
this.LayoutTrackBarParts();
this.Invalidate();
}
}
}
[DefaultValue(0)]
[RefreshProperties(RefreshProperties.All)]
public int Minimum
{
get { return minimum; }
set
{
if (minimum != value)
{
minimum = value;
if (maximum <= value)
Maximum = value;
this.LayoutTrackBarParts();
this.Invalidate();
}
}
}
[DefaultValue(10)]
public int Maximum
{
get { return maximum; }
set
{
if (maximum != value)
{
maximum = value;
if (minimum >= value)
Minimum = value;
this.LayoutTrackBarParts();
this.Invalidate();
}
}
}
[DefaultValue(1)]
public int SmallChange
{
get { return smallChange; }
set
{
if (smallChange != value)
smallChange = value;
}
}
[DefaultValue(5)]
public int LargeChange
{
get { return largeChange; }
set
{
if (largeChange != value)
largeChange = value;
}
}
public int Value
{
get
{
if (_value < this.minimum)
return this.minimum;
return _value;
}
set
{
if (value < this.minimum)
value = this.minimum;
if (value > this.maximum)
value = this.maximum;
if (value != _value)
{
_value = value;
this.LayoutTrackBarParts();
this.OnValueChanged(EventArgs.Empty);
}
}
}
private bool ShouldSerializeValue()
{
return this._value != this.minimum;
}
private void ResetValue()
{
this._value = this.minimum;
}
[DefaultValue(false)]
public new bool TabStop
{
get { return base.TabStop; }
set { base.TabStop = value; }
}
[DefaultValue("")]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public override string Text
{
get { return ""; }
set { base.Text = ""; }
}
[DefaultValue(typeof(TickStyle), "BottomRight")]
public TickStyle TickStyle
{
get { return this.tickStyle; }
set
{
if (this.tickStyle != value)
{
this.tickStyle = value;
this.Invalidate();
}
}
}
[DefaultValue(1)]
public int TickFrequency
{
get { return this.tickFrequency; }
set
{
if (this.tickFrequency != value)
{
this.tickFrequency = value;
this.Invalidate();
}
}
}
#endregion
#region private Properties
private bool Horizontal
{
get { return this.orientation == Orientation.Horizontal; }
}
private bool ThumbDragging
{
get { return thumbDragging; }
set
{
if (thumbDragging != value)
{
thumbDragging = value;
this.Invalidate();
}
}
}
#endregion
#region Overridden Methods
protected override void OnPaint(PaintEventArgs e)
{
//Do default painting
base.OnPaint(e);
//Draw Tick Marks
DrawTicks(e.Graphics);
//Draw Channel
Rectangle channelBounds = this.Horizontal ?
new Rectangle(6, this.Height / 2 - 2, this.Width - 16, 4) :
new Rectangle(this.Width / 2 - 2, 6, 4, this.Height - 16);
ControlPaint.DrawBorder3D(e.Graphics, channelBounds, Border3DStyle.Sunken);
// Draw the Thumb Object
using (SolidBrush brush = new SolidBrush(Color.Blue))
{
if (ThumbFocused)
brush.Color = Color.Green;
if (ThumbDragging)
brush.Color = Color.Red;
e.Graphics.FillRectangle(brush, this.Thumb);
}
//Draw Focus
if (this.Focused && this.ShowFocusCues)
ControlPaint.DrawFocusRectangle(e.Graphics, this.ClientRectangle);
}
protected override void OnGotFocus(EventArgs e)
{
base.OnGotFocus(e);
ThumbFocused = (this.Focused && this.ShowFocusCues);
this.Invalidate();
}
protected override void OnLostFocus(EventArgs e)
{
base.OnLostFocus(e);
ThumbFocused = (this.Focused && this.ShowFocusCues);
this.Invalidate();
}
protected override bool IsInputKey(Keys keyData)
{
switch (keyData)
{
case Keys.Up:
case Keys.Down:
case Keys.Left:
case Keys.Right:
return true;
default:
return base.IsInputKey(keyData);
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
switch (e.KeyCode)
{
case Keys.Up:
case Keys.Left:
this.Value += this.Horizontal ? -this.smallChange : this.smallChange;
break;
case Keys.Down:
case Keys.Right:
this.Value += this.Horizontal ? this.smallChange : -this.smallChange;
break;
case Keys.PageDown:
this.Value += this.Horizontal ? this.largeChange : -this.largeChange;
break;
case Keys.PageUp:
this.Value += this.Horizontal ? -this.largeChange : this.largeChange;
break;
case Keys.Home:
this.Value = this.Horizontal ? this.minimum : this.maximum;
break;
case Keys.End:
this.Value = this.Horizontal ? this.maximum : this.minimum;
break;
}
}
protected override void OnMouseWheel(MouseEventArgs e)
{
base.OnMouseWheel(e);
this.Value += (e.Delta / WHEEL_DELTA) * WHEEL_LINES;
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left)
{
ThumbDragging = Thumb.Contains(e.Location);
if (!ThumbDragging)
{
scrollUp = this.Horizontal ? e.X > Thumb.Right : e.Y < Thumb.Top;
if (scrollTimer == null)
InitTimer();
scrollTimer.Start();
}
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
ThumbDragging = false;
if (this.scrollTimer != null)
this.scrollTimer.Stop();
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (ThumbDragging)
{
this.Value = ValueFromPoint(e.Location);
}
}
protected override void OnVisibleChanged(EventArgs e)
{
base.OnVisibleChanged(e);
if (this.Visible)
this.LayoutTrackBarParts();
}
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
this.LayoutTrackBarParts();
}
#endregion
#region Protected Methods
protected virtual void OnScroll(EventArgs e)
{
if (this.Scroll != null)
this.Scroll(this, e);
}
protected virtual void OnValueChanged(EventArgs eventArgs)
{
if (this.ValueChanged != null)
this.ValueChanged(this, eventArgs);
this.LayoutTrackBarParts();
this.OnScroll(eventArgs);
this.Invalidate();
}
#endregion
#region Internal Methods
private void LayoutTrackBarParts()
{
if (Thumb == null)
return;
Thumb.Size = this.Horizontal ?
new Size(14, 28) :
new Size(28, 14);
float channelLength = this.Horizontal ?
this.Width - 26 : // Channel Left margin + Channel Right margin + Thumb.Width
this.Height - 26; // Channel Top margin + Channel Bottom margin + Thumb.Height
float stepCount = (this.Maximum - this.Minimum);
float stepSize = stepCount > 0 ? channelLength / stepCount : 0;
float thumbOffset = (stepSize) * (this.Value - this.minimum);
Thumb.Location = this.Horizontal ?
Point.Round(new PointF(6 + thumbOffset, this.Height / 2 - 14)) :
Point.Round(new PointF(this.Width / 2 - 14, channelLength - thumbOffset + 6));
}
private void InitTimer()
{
this.scrollTimer = new Timer();
this.scrollTimer.Interval = 500;
this.scrollTimer.Tick += new EventHandler(scrollTimer_Tick);
}
private void scrollTimer_Tick(object sender, EventArgs e)
{
this.Value += this.scrollUp ? this.largeChange : -this.largeChange;
if (this._value == this.minimum || this._value == this.maximum)
this.scrollTimer.Stop();
int val = this.ValueFromPoint(this.PointToClient(Cursor.Position));
if (this.scrollUp && this._value > val)
this.scrollTimer.Stop();
if (!this.scrollUp && this._value < val)
this.scrollTimer.Stop();
}
private int ValueFromPoint(Point point)
{
float channelLength = this.Horizontal ?
this.Width - 26 : // Channel Left margin + Channel Right margin + Thumb.Width
this.Height - 26; // Channel Top margin + Channel Bottom margin + Thumb.Height
float stepCount = (this.maximum - this.minimum);
float stepSize = stepCount > 0 ? channelLength / stepCount : 0;
if (this.Horizontal)
{
point.Offset(-7, 0);
return (int)(point.X / stepSize) + this.minimum;
}
point.Offset(0, -7);
return this.maximum - (int)(point.Y / stepSize) + this.minimum;
}
private void DrawTicks(Graphics graphics)
{
if (tickStyle == TickStyle.None)
return;
//TODO: Implement Tick Drawing
}
#endregion
private int WHEEL_DELTA = SystemInformation.MouseWheelScrollDelta;
private int WHEEL_LINES = SystemInformation.MouseWheelScrollLines;
}
}
by: Mick Dohertys'

Hi hope someone can help.
ReplyDeleteUsing VB.net in Visual Studio 2019
When I try to add this to a form I get an error saying Type 'TrackBar.TrackBar' is not defined.
When I click on the error it takes me to Me.TrackBar3 = New TrackBar.TrackBar().
Deleting TrackBar. gets it working again. Does anyone know what in the code is causing this?