Introduction
Recently, I came up with an idea for a program that required the ability to mimic certain aspects of a audio or lighting console. While I could find controls that could do a decent job for knobs, dials and meters, I couldn't find a decent slider control that looked anything remotely like a fader control found on these consoles.
So, I did what any self respecting self taught programmer would do while learning a new language. I decided to break my teeth on learning how to create my own custom controls in C#. Hence, the birth of the AVFader control. This is my first attempt at creating a custom control. I must say that the experience wasn't anywhere near as bad as I thought it might be, in fact, it was actually quite fun to create.
Implementation
My first attempt at this control was to try and extend the TrackBar
control and just override the OnPaint
and WndProc
methods. After discussing various pitfalls in such an implementation with a good friend of mine Fadrian, he basically told me it would be easier to just create one from scratch. Thankfully, after a quick look through the MSDN documentation, it turned out he was correct. The TrackBar
control has an unbelievable amount of Windows messages going in and out of it.
Even though I have created this control from scratch, I have tried where possible to make the properties as close to the TrackBar
settings because that control, while ugly, is very easy to use. In theory, you should be able to drop this control in over the top of an existing TrackBar
control without any hassles.
Design Constraints
You will recall that I was trying to replicate a fader as found on an audio mixing console, while also keeping it close to the TrackBar
control. Well, as with any project, I have sacrificed some features, some due to simplicity and some due to realism constraints.
- Orientation is always vertical (realism).
- Tick scale is linear not exponential (simplicity).
- Clicking on the slider track will not move the slider (realism).
- Slider movement is smooth and doesn't snap to the ticks (realism).
Please take these constraints into account when playing with this control.
Code
This is used to move the slider image when dragging the slider along the track:
private void MoveSlider(int delta)
{
if (delta < 0 && (this.picSlider.Top + delta) <= 0)
this.picSlider.Top = 0;
else if (delta > 0 && (this.picSlider.Top
+ this.picSlider.Height + delta) >= this.Height)
this.picSlider.Top = this.Height - this.picSlider.Height;
else
this.picSlider.Top += delta;
this.CalculateSliderValue();
}
This is used to move the slider based on the value of the Value
property:
private void MoveSlider()
{
int distance = Math.Abs(this._maxValue) + Math.Abs(this._minValue);
float percent = (float)this._value / (float)distance;
this.picSlider.Top = this.Height - this.Top -
Convert.ToInt32(percent * (float)(this.Height - this.picSlider.Height));
}
And lastly, this one is pretty self explanatory, it calculates the value of the Value
property based on the location of the slider image on the control:
private void CalculateSliderValue()
{
int distance = this.Height - this.picSlider.Height;
float percent = (float)this.picSlider.Top / (float)distance;
int movement = Convert.ToInt32(percent * (float)(Math.Abs(this._maxValue)
+ Math.Abs(this._minValue)));
this._value =
(this._maxValue >= 0) ? this._maxValue -
movement : this._maxValue + movement;
ValueChanged(this, new EventArgs());
}
Conclusion
Overall, I'm quite happy with this as a first attempt at control development. It does what I need it to do, and also without exploding in my face. Hopefully, someone else can find this useful as well.