When using TabControl in my programs, usually there is one thing users always ask for – “let me reorder those tabs”. Since reordering tabs is such a logical operation, one would think that the mighty .NET 2.0 Framework has one. But no luck there. Visual Studio 2008 does have that feature, but framework mortals are not blessed with it.
Since Visual Basic programmers waited for inheritance for far too long, they tend to use it for solving every possible problem (when you have a hammer, all problems look like nails). May I say that here, the same inheritance approach will be used. :)
What we want to do here is to extend the standard TabControl. Inside of it, we are interested in MouseDown, MouseMove and MouseUp events. Some people like to use drag and drop here, but that seems to me like using a bomb to kill a fly.
Upon receiving a MouseDown event, we check if the Left button is used and if TabControl has tab selected. If those requirements are fulfilled, we initialize the SourceTabPage variable. With that, we are ready for further events.
When the mouse is moved, one must check if reordering is in progress. If that is true, we look at what TabPage is under it. If it is not starting one – we have a show.
One of the things we must discover is which TabPage we are hovering over. Since unfortunately, we cannot use some sort of HitText, we must iterate through all TabPages and select one with our coordinates.
After that, we check which side we are hovering. It is only important if you wish to display a different cursor for each side. These two are the ones I use, but you can think of your own schema.
Here, we must know on which side we are since the new location (before or after hovering TabPage) depends on this information. This code is basically the same as the one we use for determining the cursor type. After clearing is done, so is our function.
This extended control offers a good solution to reordering TabPages inside a TabControl. I think that the only thing one may hold against it is updating the order on MouseUp but that decision is made for the sake of speed and code clarity. This way, it is very easy to implement changes through further extending since it uses protected OnMouseX procedures.
This is redoing of my Code Project article.