A custom range selector control in C# (with a little animating slider)

At times, business needs are so unique that we have to write new controls in addition to the existing Toolbox provided controls. This article explains how to write such a unique control, named Range Control. Control source and a sample app are included.

New version 1.5: Little animation and snap feature

Old version 1.0

The first link contains the binaries to watch a quick demo. The second link contains the Range control source code and a test application source code that uses this control.

Introduction

It's a fine morning. Your boss Alice says, "Hey Bob! It will be great if we can have a unique control matching our business needs instead of presenting a legacy one. bla bla bla....". And you think, "Well, it *was* a fine morning ... ". However, now you have to design a unique custom control matching your unique business needs.

This article details how to write your own unique custom control. Also, this article includes a sample animated range selection control (both binary and source code included). The initial sections of this article explains how to use the range control. If you are an advanced programmer, you may directly go to the 'Control code explained' section after seeing the demo.

Background

Business needs are not always very generic. Most of the time, business needs are very unique and require authoring a custom control.

Using the code

Steps to see a demo:

Step 1: Copy the binaries (download using the link from the top of this article) to a separate folder.

Step 2: It is a compressed file. Choose a temporary folder and copy all the files into the folder.

Step 3: Run TestApplication.exe.

Step 4: You should see an application as in the image above.

You can slide the slider thumb in both directions using your mouse. I chose to have a smooth scroll slider instead of a block move slider. However, the code can be modified to support both. Also, I added a little animation for good user experience.

Steps to use the assembly:

Consider you are done seeing the demo and would like to use it. The following steps may be followed to use the Range Selector custom control in your project:

Step 1: Create a Windows Forms application using Visual Studio 2005 or above. The VS2005 requirement is because, I compiled the assembly in VS2005. However, you can easily move it to any version of Visual Studio with very little effort

Step 2: In the Toolbox, right click, then select 'Choose Items'. Then, click the Browse button to choose the assembly. Click the OK button after selecting the assembly.

Step 3: Now, you will see an entry in the Toolbox with the name 'RangeSelectorControl'. Drag and drop it to any part of your Windows form to use the control.

Step 6: Now, it's coding time. But, it's very minimal. All you have to do is register your method with the control assembly -- so that the control assembly will call your method when the user changes his choice (by sliding the range control). Otherwise, you can also query the control method QueryRange to find out the user choice. Both the choices are explained with a simple code snippet below.

In the above code snippet, the first line declares two string variables strRange1 and strRange2. The next line queries the control assembly to get the current user choice. After which, the code updates a TextBox control in the form to showcase the user choice.

Now, another option is to get continuous update from the control whenever a user modifies his option. Look at the code snippet below:

In the above code, the first line declares a class level variable objNotifyClient. This variable is initialized in the Form_Load event. Next, this object is registered with the control assembly for continuous notifications.

However, I included a detailed sample test application for those who use this control assembly extensively. The sample source code and the control source code can be downloaded from the link at the top of this article.

As always, this is not a professional level code. Hence, I have not done extreme validation checks in the code. However, the code can be brushed up quickly.

Points of interest

Okay, now, about writing a control assembly. It's very simple. All you have to do is create a new control project. If you have created the project correctly, your main class will derive from System.Windows.Forms.UserControl. All you have to do then is manage your control's visual activity by overriding the void OnPaint(PaintEventArgs e) method. You can look at the source code of range selector control. It's very simple with a few math calculations. Based on the comments I have received, I will explain this in further detail.

These are a few interesting things I did in the range selector control:

The range selector control exposes as much properties as possible to give users an opportunity to see the control at design time rather than at runtime.

Ranges can be input using an XML file. This will help to load the control in a much generic way.

The range selector control accepts bitmaps.

The range selector control avoids any flicker while moving the slider using the mouse.

The range selector control automatically displays the range values at the bottom.

I have also added a little animation, which is explained in the next section (Control code explained - seventh section/region).

Control code explained

Refer to the range selector control source code (and the demo) that can be downloaded from the links at the top of this article.

I divided the control source code in the namespace CustomRangeSelectorControl.RangeSelectorControl into different regions. Let’s walk through the regions one by one.

The first region is 'Design Time Control Variables...'. These are private variables that will hold the values of the exposed properties to the users. For example, strXMLFileName is used to store the value of the exposed property XMLFileName.

The second region is 'Design Time Control Properties...'. These are the properties exposed to the user of the control at design time. For example, have a look at the first property XMLFileName. Open the demo in Visual Studio. Right click to see the properties of this control. If you browse through entry by entry, you will find the XMLFileName property exposed to the user. The user can type in the value using Visual Studio designer's property window. You can see all the properties such as RangeString, RangeValues, LabelFont etc., in this section. The code below is just a small snippet from this region.

The third region is 'Variables used for computation'. These are the variables used to do the math calculations when the user moves the slider. Also, these variables are used to draw the bitmap, font, line, slider, and the bar at the right locations at the right time.

The fourth region is the constructor for this control. This constructor contains a region 'Initialization of variables'. This region contains code that initializes all the declared variables with default values for this class.

Fifth region is 'Methods exposed to client at runtime'. The users of this range control needs to receive feedback from the control about user activity. Consider that an end user of the application slides a bar in the range selector control, then the application needs to receive input to these events to act on. There are two methods exposed for this purpose. One is passive and the other is active. The passive one is a query method. The user of this control can query the control at any given time to get the current range values selected by the application's end user. Otherwise, the application can register for a notification to be sent out when the user slides the control. The method QueryRange does the passive job and the RegisterForChangeEvent method does the active job.

The sixth region is 'This is a Private method that calculates the values...". This section has only one private method CalculateValues. This method calculates the values to draw the various components of the control. The various components of the control are the bar, slider, range values etc. The code is well documented here. It gets the Graphics object, then calculates the positions of each component.

The seventh region is 'Paint Method override'. This is the important one that draws the control on the screen. The code is very simple here. The first for loop draws the Labels on the screen. The next one draws the range values on the screen. The next draws Slider1 (mentioned in the code as Thumb1) and Slider2. The following lines in this method are to draw the in-focus and disabled colors properly based on the calculated values using the above section.

I implemented a very simple animation in this paint method. This is not a very professional one, but provides a basic understanding of the animation. Once the mouse is up, we set the bAnimateSlider to true. This is used in the paint method to repeatedly call the Draw method to animate. However, if the animation takes longer than a second (1000 ms), then we discard the animation.

The eighth region is 'Methods used for handling mouse events'. This section has methods to capture the mouse events up, down, and move. These methods are used to see if the mouse activity by the end user is interesting enough.

The last region is 'Notification class...'. This section contains a small class that the user may pass to get an active event notification.

///<spanclass="code-SummaryComment"><RangeSelectorControl_Resize></span>/// The below is the small Notification class that can be used by the client
///<spanclass="code-SummaryComment"></RangeSelectorControl_Resize></span>///#region Notification classfor client to register with the control for changes
publicclass NotifyClient
{
privatestring strRange1, strRange2;
publicstring Range1
{
set
{
strRange1 = value;
}
get
{
return strRange1;
}
}
publicstring Range2
{
set
{
strRange2 = value;
}
get
{
return strRange2;
}
}
}
///<spanclass="code-SummaryComment"><RangeSelectorControl_Resize></span>/// The Above is the small Notification class that can be used by the client
///<spanclass="code-SummaryComment"></RangeSelectorControl_Resize></span>///#endregion

History

21 Aug 2008 - First version. Added source snippets in the 'Control code explained' section. Added snap feature as suggested by a reviewer. Added another version with a little animation.

I am new to C# winform I have a Track bar i want to adjust the track bar with rangeControl which is downloaded from code project. I don't know how to configure this with c# if any one know please help me .Thanks in advance

This is a unique custom control. i.e., Like a unique stand alone control that can be used in your project. I am not sure if you can use it with your track bar readily. Can you pl explain more on your intentions - Tx

Thanks for your reply, I am applying value 0-100 for track bar, i am converting the video length and i am assigning to the track bar. If i move the track bar means the video will be adjusted. like wise if i adjust the range control means the track bar value should be adjusted. So that we a able to cut a video for a particular range by getting the value from range control start and end range. How can i do this in c# Win form. I have struck in this for a long period please help me. Thanks in advance.

I think there are subscribe methods provided in the Range Selection control that is published in this article. Your track bar should subscribe to this method to receive notification. Then, you will be able to use that notification to tailor your video length

Hi, Sir
I have been asked to do a task like this but that is impossible. The requirement is that to show 2000 values onto Slider and they can bee seen. in a form. that is impossible to do.Sir. in my mind it goes that if add Horizontal Scroll and place our control onto it, we might add up values and can expand our control as long as the length of values.? kindly guide me. is it a doable and how?

I don't understand why there isn't a simple event like "Range1_Changed".
That's how all other controls work. Button_Click. ComboBox_SelectedIndexChanged. Etc. etc.
Why build this nice control then not make a couple standard events like "Minimum_Changed" and "Maximum_Changed"? I must be missing some understanding of an advantage to doing it with the NotifyClient class.

private void RangeSelectorControl_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
// If the Mouse is Up then set the Event to false
bMouseEventThumb1 = false;
bMouseEventThumb2 = false;