Click here to Skip to main content
15,172,297 members
Articles / Multimedia / GDI
Article
Posted 11 Sep 2015

Stats

107.7K views
19.1K downloads
68 bookmarked

ToggleSwitch Winforms Control

Rate me:
Please Sign up or sign in to vote.
4.98/5 (71 votes)
11 Sep 2015CPOL7 min read
A ToggleSwitch that presents on/off values in a more interesting way than a standard CheckBox

Introduction

So, once again, I'm publishing an article about a custom painted Winforms control. I guess I ought to change my profile name to "Control Freak"... But what the heck: I love programming custom controls! Nothing to do about that.

This time, I needed a ToggleSwitch or ToggleButton - something that can show a binary On/Off Checked/Unchecked state in a more interesting way than the standard checkbox. As usual, I started checking out the existing controls, because who wants to spend a lot of time reinventing something that has already been invented??? The thing that normally happens to me also happened this time: I found existing controls that could have been so great, but was leaving me wanting in some way. The best I could find (and very good looking too at that) is this one by IKalai (here on Code Project of course). But I had some problems with Ikalai's control. The most important one was that it doesn't allow you to change the size of the control as you want, and I couldn't make it the size I needed for my application... :-( I really don't understand why he has chosen to impose such a strange limitation on his control!

I also found this one, which is even better looking - but alas, it is built for WPF/Silverlight, so I couldn't use it.

So I did what I so often do: I started rolling my own control. And as usual, I went completely overboard and made it much more advanced than I really needed. Instead of merely doing a control that looked as I wanted and behaved as I wanted, I was inspired by the above two articles to make a control that could be made to look in a lot of different ways. In the end, I wound up with TEN different styles plus the possibility to customize those styles further - AND create own renderers to add even more styles if one should feel the need to do that.

The articles didn't just inspire me, I must admit that I even stole some ideas from them... But the code is 100% mine!

In the end - after finishing the control - I got a completely different idea. So I'm not even sure I'm going to use my ToggleSwitch in the application I created it for. But here it is, nevertheless, for the benefit of y'all to use.

Control Feature Overview

1. Basic Control Goodies

The control is of course doublebuffered to minimize flicker. It is also derived from the Control class so it supports both the Anchor and Dock properties.

2. Different Styles

Image 1

I planked two styles from IKalai's control and seven from the WPF control. The style is changed by merely setting the Style property to the style you want.

3. Image and Text Support

You can customize the control pretty much as you like. A text or image can be inserted in each side of the control (if the selected renderer supports it). You can only have either text OR image. If you have set the image property, it will take precedence and the text property will not be used.

Image 2

You can also insert an image in the button itself (again if the selected renderer supports it). I didn't implement the text option for the slider button because my judgment was that the text that could fit in the button would be so small anyway that it is of no use.

4. Other Cool Properties

  • AllowUserChange - There may be situations where you don't want the user to be able to change the value of the control, but you don't want to disable it either. If you set AllowUserChange = false, the user cannot change the value, but you can still change it in code behind.

  • AnimationInterval, AnimationStep & UseAnimation - When the slider moves from one state to another, it can be animated. When UseAnimation = true, the two other values determine how fast the button moves. Generally, it is moved the number of pixels set in AnimationStep for each number of milliseconds set in AnimationInterval. If you want the button to change state immediately, just set UseAnimation = false.

  • GrayWhenDisabled - Determines if the control is painted in grayscale when it is disabled or retains the same look as when it is enabled.

    Image 3

  • ThresholdPercentage - Determines how far you have to drag the button before it snaps to the other side. Default is 50%, so if you pull the slider button more than halfways across the control, it will automatically snap to the other side. The percentage is always calculated from the side where the button currently resides.

  • ToggleOnButtonClick & ToggleOnSideClick - The user can of course always drag the slider button to change the value of the switch. But using these properties, you can also decide if the control should toggle if it is clicked by the user. If ToggleOnButtonClick = true, clicking the slider button will toggle the switch. If ToggleOnSideClick = true, you can even click the areas beside the button and get the switch to toggle. If both are true, clicking anywhere on the control will toggle it, and if both properties are false, clicking the control will have no effect at all.

5. Customizable Renderers

Each style has its own renderer. Some of the basic properties such as the image properties are so common that they can be found directly on the ToggleSwitch control. Not all renderes accept all these properties, though. But most of them do. Other properties such as colors, I've chosen to attach to the specific renderers. Because they all paint the controls in so different ways, it was hard to make general color properties in the ToggleSwitch control that would make sense in all the different scenarios.

Image 4

By making the color properties part of the renderers, it's possible to customize the look of a specific style much more than it would otherwise have been. The drawback is that in order to do that, you have to create a new instance of the renderer, change the properties and assign the new renderer to the control. But it's not that hard and the demo program shows exactly how to do that.

In version 1.1 of the control, I am passing the renderer instance in a BeforeRendering event so that the properties can be set directly without creating a new instance first.

Points of Interest

The look I originally wanted for my application was the one with the brushed metal knob. All the controls I have seen with brushed metal knobs before have done them in the same way: By embedding an image file created in PhotoShop in the resources and paint that on the surface of the control. I found a PhotoShop tutorial on how to create such an image...

But it disturbed me and my touch of Asperger. Embedding a file and painting that is not so "clean" as if you paint it directly on the control yourself.

Even with the PhotoShop tutorial, I didn't really know how to paint it in C#. I asked some people on Code Project, but I didn't really get much help there. Pete told me that I had to use a gradient brush - which I already knew, but I couldn't really see how i could do it anyway. So I Googled some more. I found a lot of examples on how to fill a circle with a radial gradient using a PathGradientBrush. But all of those examples showed how to make a gradient that went from the inner center of the circle to the outer border (or the other way around). And I of course needed to make a gradient that went around the inside of the circle.

It wasn't easy, but FINALLY, I found this example that does more or less what I needed:

So I started dividing the image of the metal knob into gradient pie slices and paint them one by one. That worked out, But strangely enough, I discovered that if I painted all the gradients using the actual center of the knob as center for the brushes, I didn't get the look I had expected. To get the correct look, I had to offset the center of each brush slightly. I don't know why, but I got it to work in the end, I think.

"My" painted brushed metal knob may not look EXACTLY as good as a PhotoShopped one, but I was quite pleased with the result anyway. More so that I didn't have to include resources in the control library to get it to work.

History

Version 1.1 (2019-02-20)

  • NEW: BeforeRendering event added to make it easier to customize the renderer properties
  • NEW: Style and Renderer added: PlainAndSimple
  • UPDATED: Demo app updated with the new features

Version 1.0 (2015-09-11)

  • Initial release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Johnny J.
Software Developer (Senior)
Sweden Sweden
Born in Copenhagen, Denmark
Have been living in Paris, France and L.A., The United States
Now live in Stockholm, Sweden

Started programming when I got my first VIC 20, and a few months later on Commodore 64. Those were the days!

Studied programming at the Copenhagen Engineering Academy

Professional console, winforms and webforms programming in Comal, x86 Assembler, Fortran, Pascal, Delphi, Visual Basic 3 through 6, Classic ASP, C# and VB.NET

I now work as Senior Microsoft Dynamics AX and .Net programmer, and have a number of projects in various states of progress to work on in the spare time...

Comments and Discussions

 
GeneralMy vote of 5 Pin
olivier gg10-Jan-22 4:32
Memberolivier gg10-Jan-22 4:32 
QuestionMy Vote of 5! Pin
Behzad Sedighzadeh9-Aug-21 10:38
MemberBehzad Sedighzadeh9-Aug-21 10:38 
QuestionWould like to use these in VB.NET Pin
nor s26-Jul-21 4:51
Membernor s26-Jul-21 4:51 
AnswerRe: Would like to use these in VB.NET Pin
Johnny J.27-Jul-21 6:43
professionalJohnny J.27-Jul-21 6:43 
GeneralRe: Would like to use these in VB.NET Pin
nor s27-Jul-21 9:12
Membernor s27-Jul-21 9:12 
Questioncan you create github repository, to permit du contribut to the project! Pin
Mathieu CARBONNEAUX25-May-21 10:23
MemberMathieu CARBONNEAUX25-May-21 10:23 
QuestionNice Control - Pushed to GitHub and NuGet Pin
Code Artist30-Jan-21 3:29
professionalCode Artist30-Jan-21 3:29 
SuggestionNice control, one suggestion Pin
Huisman121214-Dec-20 6:30
MemberHuisman121214-Dec-20 6:30 
QuestionOrientation Pin
Peter Dodson7-Oct-20 5:01
MemberPeter Dodson7-Oct-20 5:01 
QuestionIs the control available for Delphi ? Pin
Member 1494729823-Sep-20 21:53
MemberMember 1494729823-Sep-20 21:53 
PraiseThanks Pin
Member 134612483-Aug-20 17:56
MemberMember 134612483-Aug-20 17:56 
QuestionAwesome switches. Have a question. Pin
Member 1478476027-Mar-20 6:37
MemberMember 1478476027-Mar-20 6:37 
PraiseLove this control !! Pin
Member 1465469913-Nov-19 11:32
MemberMember 1465469913-Nov-19 11:32 
QuestionDon't Forget Pin
RonW228-Sep-19 11:17
MemberRonW228-Sep-19 11:17 
QuestionPlainSimple Pin
corlleonedonss20-Sep-19 3:37
Membercorlleonedonss20-Sep-19 3:37 
AnswerRe: PlainSimple Pin
RonW228-Sep-19 12:11
MemberRonW228-Sep-19 12:11 
QuestionToggle switch zip Pin
Member 145205825-Jul-19 5:03
MemberMember 145205825-Jul-19 5:03 
QuestionThanks! Pin
Ignacioooooo24-Jun-19 6:28
MemberIgnacioooooo24-Jun-19 6:28 
QuestionNice Pin
AlexGambler7-Jun-19 0:00
MemberAlexGambler7-Jun-19 0:00 
QuestionFantastic job! Pin
Ignacioooooo6-Jun-19 3:50
MemberIgnacioooooo6-Jun-19 3:50 
QuestionImprovement Suggestion: Indeterminate State Pin
MrBjorn11-Mar-19 2:42
MemberMrBjorn11-Mar-19 2:42 
A third state, like checkboxes have in winforms. So the user have to make an active choice. Could be that the switch is in the middle position for instance, with some text indicating this.
GeneralMy vote of 4 Pin
Jose Luis Rey21-Feb-19 19:25
MemberJose Luis Rey21-Feb-19 19:25 
QuestionVery nice control! Pin
MrBjorn15-Feb-19 6:05
MemberMrBjorn15-Feb-19 6:05 
AnswerRe: Very nice control! Pin
Johnny J.20-Feb-19 1:55
professionalJohnny J.20-Feb-19 1:55 
QuestionHelp with implementation Pin
Member 1188311325-Jan-19 5:14
MemberMember 1188311325-Jan-19 5:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.