I've created a trackbar
component with 2 meters, plus when I manually render it in xaml
, barra
and marcadores
misconfigure and barra
goes up and marcadores
goes by.
Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
namespace TrackBarDouble
{
public partial class DoubleTrackbar : UserControl
{
#region Internal Enumerator
public enum Thumbs
{
None = 0,
Left = 1,
Right = 2,
}
#endregion
#region Constructor
public DoubleTrackbar()
{
InitializeComponent();
this.AutoSize = true;
this.DoubleBuffered = true;
this.SetDefaults();
}
#endregion
#region Declarations
private int _minimum;
private int _maximum;
private int _valueRight;
private int _valueLeft;
public event EventHandler ValueChanged;
public event EventHandler LeftValueChanged;
public event EventHandler RightValueChanged;
private TrackBarThumbState leftThumbState;
private TrackBarThumbState rightThumbState;
private bool draggingLeft, draggingRight;
private Thumbs selectedThumb;
#endregion
#region Properties
[Description("Orientação do Slider")]
[DefaultValue(typeof(Orientation), "Horizontal")]
public Orientation Orientation
{
get;
set;
}
[Description("Valor de mudança mínima para cada seletor")]
public int SmallChange
{
get;
set;
}
[Description("Valor mínimo do trackbar")]
public int Minimum
{
get { return _minimum; }[![inserir a descrição da imagem aqui][1]][1]
set
{
if (value >= Maximum)
throw new ArgumentException(String.Format("Valor de '{0}' não é válido para 'Minimum'. 'Minimum' deve ser menor que 'Maximum'.", value.ToString()), "Minimum");
_minimum = value;
this.Invalidate();
}
}
[Description("Valor máximo do trackbar")]
public int Maximum
{
get { return _maximum; }
set
{
if (value <= Minimum)
throw new ArgumentException(String.Format("Valor de '{0}' não é válido para 'Maximum'. 'Maximum' deve ser maior que 'Minimum'.", value.ToString()), "Maximum");
_maximum = value;
this.Invalidate();
}
}
[Description("Valor do seletor direito")]
public int ValueRight
{
get { return _valueRight; }
set
{
if (((value < this.Minimum)
|| (value > this.Maximum)))
{
throw new ArgumentException(string.Format("Valor de \'{0}\' não é válido para \'ValueRight\'. \'ValueRight\' deve estar entre \'Minimum\' e \'Maximum\'.", value.ToString()), "ValueRight");
}
if ((value <= this.ValueLeft))
{
value = this.ValueLeft;
}
_valueRight = value;
this.OnValueChanged(EventArgs.Empty);
this.OnRightValueChanged(EventArgs.Empty);
this.Invalidate();
}
}
[Description("Valor do seletor esquerdo")]
public int ValueLeft
{
get { return _valueLeft; }
set
{
if (((value < this.Minimum) || (value > this.Maximum)))
throw new ArgumentException(string.Format("Valor de \'{0}\' não é válido para \'ValueLeft\'. \'ValueLeft\' deve estar entre \'Minimum\' e \'Maximum\'", value.ToString()), "ValueLeft");
if ((value > this.ValueRight))
throw new ArgumentException(string.Format("Valor de \'{0}\' não é válido para \'ValueLeft\'. \'ValueLeft\' deve ser menor que \'ValueRight\'", value.ToString()), "ValueLeft");
_valueLeft = value;
this.OnValueChanged(EventArgs.Empty);
this.OnLeftValueChanged(EventArgs.Empty);
this.Invalidate();
}
}
[Description("Retorna qual seletor está em uso")]
public Thumbs SelectedThumb
{
get { return selectedThumb; }
private set { selectedThumb = value; }
}
#region Private Properties
private double RelativeValueLeft
{
get
{
double diff = this.Maximum - this.Minimum;
return (diff != 0) ? (this.ValueLeft / diff) : this.ValueLeft;
}
}
private double RelativeValueRight
{
get
{
double diff = (this.Maximum - this.Minimum);
return (diff != 0) ? (this.ValueRight / diff) : this.ValueLeft;
}
}
#endregion
#endregion
#region Internal Events Implementation
protected void OnValueChanged(EventArgs e)
{
if (ValueChanged != null)
ValueChanged(this, e);
}
protected void OnLeftValueChanged(EventArgs e)
{
if (LeftValueChanged != null)
LeftValueChanged(this, e);
}
protected void OnRightValueChanged(EventArgs e)
{
if (RightValueChanged != null)
RightValueChanged(this, e);
}
#endregion
#region Private Methods
private void SetDefaults()
{
this.Orientation = Orientation.Horizontal;
this.SmallChange = 1;
this.Maximum = 10;
this.Minimum = 0;
this.ValueRight = Maximum - 1;
this.ValueLeft = Minimum + 1;
}
private Rectangle GetLeftThumbRectangle(Graphics g)
{
if (g == null)
g = this.CreateGraphics();
Rectangle rect = this.GetThumbRectangle(this.RelativeValueLeft, g);
if (g == null)
g.Dispose();
return rect;
}
private Rectangle GetRightThumbRectangle(Graphics g)
{
if (g == null)
g = this.CreateGraphics();
Rectangle rect = this.GetThumbRectangle(this.RelativeValueRight, g);
if (g == null)
g.Dispose();
return rect;
}
private Rectangle GetThumbRectangle(double relativeValue, Graphics g)
{
if (Orientation == Orientation.Horizontal)
{
Size size = TrackBarRenderer.GetBottomPointingThumbSize(g, TrackBarThumbState.Normal);
int border = size.Width / 2;
int w = this.GetTrackRectangle(border).Width;
int x = Convert.ToInt16(Math.Round(((Math.Abs(this.Minimum) / ((this.Maximum - this.Minimum) * w)) + (relativeValue * w)), 0));
int y = (this.Height - size.Height) / 2;
return new Rectangle(new Point(x, y), size);
}
else
{
Size size = TrackBarRenderer.GetBottomPointingThumbSize(g, TrackBarThumbState.Normal);
int border = size.Height / 2;
int w = this.GetTrackRectangle(border).Height;
int x = Convert.ToInt16(Math.Round(((Math.Abs(this.Minimum) / ((this.Maximum - this.Minimum) * w)) + (relativeValue * w)), 0));
int y = (this.Width - size.Width) / 25;
return new Rectangle(new Point(y, x), size);
}
}
private Rectangle GetTrackRectangle(int border)
{
if (Orientation == Orientation.Horizontal)
{
return new Rectangle(border, (Convert.ToInt16(this.Height / 2) - 3), (this.Width - ((3 * border) - 1)), 10);
}
else
{
return new Rectangle(border, (Convert.ToInt16(this.Width / 10) - 2), 10, (this.Height - ((3 * border) - 1)));
}
}
private bool IsValidValueLeft(int value)
{
return ((value >= this.Minimum) && ((value <= this.Maximum) && (value < this.ValueRight)));
}
private bool IsValidValueRight(int value)
{
return ((value >= this.Minimum) && ((value <= this.Maximum) && (value > this.ValueLeft)));
}
private void SetThumbState(Point location, TrackBarThumbState newState)
{
Rectangle leftThumbRect = this.GetLeftThumbRectangle(null);
Rectangle rightThumbRect = this.GetRightThumbRectangle(null);
if (leftThumbRect.Contains(location))
leftThumbState = newState;
else if ((this.SelectedThumb == Thumbs.Left))
leftThumbState = System.Windows.Forms.VisualStyles.TrackBarThumbState.Hot;
else
leftThumbState = System.Windows.Forms.VisualStyles.TrackBarThumbState.Normal;
if (rightThumbRect.Contains(location))
rightThumbState = newState;
else if ((this.SelectedThumb == Thumbs.Right))
rightThumbState = System.Windows.Forms.VisualStyles.TrackBarThumbState.Hot;
else
rightThumbState = System.Windows.Forms.VisualStyles.TrackBarThumbState.Normal;
}
private Thumbs GetClosestSlider(Point point)
{
Rectangle leftThumbRect = this.GetLeftThumbRectangle(null);
Rectangle rightThumbRect = this.GetRightThumbRectangle(null);
if ((this.Orientation == Orientation.Horizontal))
{
if (((Math.Abs((leftThumbRect.X - point.X)) > Math.Abs((rightThumbRect.X - point.X)))
&& ((Math.Abs((leftThumbRect.Right - point.X)) > Math.Abs((rightThumbRect.Right - point.X))))))
{
return Thumbs.Right;
}
else
return Thumbs.Left;
}
else
{
// Vertical Slider doesn't work. It took me long enough to type in the horizontal. Have fun with it!
if (((Math.Abs((leftThumbRect.Y - point.Y)) > Math.Abs((rightThumbRect.Y - point.Y)))
&& (Math.Abs((leftThumbRect.Bottom - point.Y)) > Math.Abs((rightThumbRect.Bottom - point.Y)))))
{
return Thumbs.Right;
}
else
{
return Thumbs.Left;
}
}
}
#endregion
#region Overrided Events
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (Orientation == Orientation.Horizontal)
{
Size thumbSize = this.GetThumbRectangle(0, e.Graphics).Size;
Rectangle trackRect = this.GetTrackRectangle(Convert.ToInt16(thumbSize.Width / 2));
Rectangle ticksRect = trackRect;
ticksRect.Offset(0,15);
TrackBarRenderer.DrawVerticalTrack(e.Graphics, trackRect);
TrackBarRenderer.DrawVerticalTicks(e.Graphics, ticksRect, ((this.Maximum - this.Minimum) + 1), System.Windows.Forms.VisualStyles.EdgeStyle.Etched);
TrackBarRenderer.DrawRightPointingThumb(e.Graphics, this.GetLeftThumbRectangle(e.Graphics), leftThumbState);
TrackBarRenderer.DrawRightPointingThumb(e.Graphics, this.GetRightThumbRectangle(e.Graphics), rightThumbState);
}
else
{
Size thumbSize = this.GetThumbRectangle(0, e.Graphics).Size;
Rectangle trackRect = this.GetTrackRectangle(Convert.ToInt16(thumbSize.Height / 2));
Rectangle ticksRect = trackRect;
ticksRect.Offset(15, 0);
TrackBarRenderer.DrawVerticalTrack(e.Graphics, trackRect);
TrackBarRenderer.DrawVerticalTicks(e.Graphics, ticksRect, ((this.Maximum - this.Minimum) + 1), System.Windows.Forms.VisualStyles.EdgeStyle.Etched);
TrackBarRenderer.DrawRightPointingThumb(e.Graphics, this.GetLeftThumbRectangle(e.Graphics), leftThumbState);
TrackBarRenderer.DrawRightPointingThumb(e.Graphics, this.GetRightThumbRectangle(e.Graphics), rightThumbState);
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
this.SetThumbState(e.Location, TrackBarThumbState.Hot);
double offset = ((double)e.Location.X / this.Width) * (this.Maximum - this.Minimum);
int newValue = (this.Minimum + Convert.ToInt16(offset));
if (draggingLeft && this.IsValidValueLeft(newValue))
this.ValueLeft = newValue;
else if (draggingRight && this.IsValidValueRight(newValue))
this.ValueRight = newValue;
this.Invalidate();
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
this.Focus();
this.SetThumbState(e.Location, TrackBarThumbState.Pressed);
draggingLeft = (leftThumbState == TrackBarThumbState.Pressed);
draggingRight = (rightThumbState == TrackBarThumbState.Pressed);
this.SelectedThumb = draggingLeft ? Thumbs.Left : draggingRight ? Thumbs.Right : Thumbs.None;
if (!draggingLeft && !draggingRight)
{
if ((this.GetClosestSlider(e.Location) == Thumbs.Left))
{
if ((e.X < this.GetLeftThumbRectangle(null).X))
this.DecrementLeft();
else
this.IncrementLeft();
this.SelectedThumb = Thumbs.Left;
}
else if ((this.GetClosestSlider(e.Location) == Thumbs.Right))
{
if ((e.X < this.GetRightThumbRectangle(null).X))
this.DecrementRight();
else
this.IncrementRight();
}
this.SelectedThumb = Thumbs.Right;
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
draggingLeft = false;
draggingRight = false;
this.Invalidate();
}
protected override void OnMouseWheel(MouseEventArgs e)
{
base.OnMouseWheel(e);
if ((e.Delta == 0))
return;
if ((this.SelectedThumb == Thumbs.Left))
{
if ((e.Delta > 0))
this.IncrementLeft();
else
this.DecrementLeft();
}
else if ((this.SelectedThumb == Thumbs.Right))
{
if ((e.Delta > 0))
this.IncrementRight();
else
this.DecrementRight();
}
}
#endregion
#region Public Methods
/// <summary>
/// Incrementa 1 no valor e posição do seletor esquerdo
/// </summary>
public void IncrementLeft()
{
int newValue = Math.Min((this.ValueLeft + 1), this.Maximum);
if (this.IsValidValueLeft(newValue))
this.ValueLeft = newValue;
this.Invalidate();
}
/// <summary>
/// Incrementa 1 no valor e posição do seletor direito
/// </summary>
public void IncrementRight()
{
int newValue = Math.Min((this.ValueRight + 1), this.Maximum);
if (this.IsValidValueRight(newValue))
this.ValueRight = newValue;
this.Invalidate();
}
/// <summary>
/// Decrementa 1 no valor e posição do seletor esquerdo
/// </summary>
public void DecrementLeft()
{
int newValue = Math.Max((this.ValueLeft - 1), this.Minimum);
if (this.IsValidValueLeft(newValue))
this.ValueLeft = newValue;
this.Invalidate();
}
/// <summary>
/// Incrementa 1 no valor e posição do seletor direito
/// </summary>
public void DecrementRight()
{
int newValue = Math.Max((this.ValueRight - 1), this.Minimum);
if (this.IsValidValueRight(newValue))
this.ValueRight = newValue;
this.Invalidate();
}
#endregion
}
}