Click here to Skip to main content
15,867,453 members
Please Sign up or sign in to vote.
2.67/5 (3 votes)
Does anyone here know of a good, free (preferably) toggle switch style control for winforms? (e.g. like the switch control in iOS).
Posted
Comments
Sergey Alexandrovich Kryukov 22-Oct-12 20:57pm    
Not clear. What exactly should it do? How about a check box all it does is toggle :-)
--SA
Brisingr Aerowing 22-Oct-12 21:20pm    
It should act like the switch control in iOS.
Brisingr Aerowing 22-Oct-12 21:22pm    
Like the on/off switches in the iOS options area. Just as TheCardinal suggested.
Sergey Alexandrovich Kryukov 22-Oct-12 23:48pm    
Sure, thank you for the confirmation. Please see my comment to TheCardinal solution.
--SA

i have created a custom control for my metro ui look, the toggle control from the windows 8 pc settings

create a usercontrol and add 1 label

C#
public partial class ToggleSwitch : UserControl
   {
       public Color ColorToggleOn { get; set; }
       public bool istoggleStatus { get; set; }

       public ToggleSwitch()
       {
           InitializeComponent();
       }

       private void ToggleSwitch_Load(object sender, EventArgs e)
       {
           if (istoggleStatus) {
               isON();
           }
           else {
               isOFF();
           }
       }

       protected override void OnMouseDown(MouseEventArgs e)
       {
           base.OnMouseDown(e);
           SetToggleControlStatus(istoggleStatus);
       }

       private void SetToggleControlStatus(bool isToggle)
       {
           if (isToggle) {
               isToggle = false;
               this.BackColor = Color.Silver;
               this.label1.Dock = DockStyle.Left;
           }
           else {
               isToggle = true;
               this.BackColor = this.ColorToggleOn;
               this.label1.Dock = DockStyle.Right;
           }
           istoggleStatus = isToggle;
       }

       private void isOFF()
       {
           this.BackColor = Color.Silver;
           this.label1.Dock = DockStyle.Left;
       }

       private void isON()
       {
           this.BackColor = ColorToggleOn;
           this.label1.Dock = DockStyle.Right;
       }

       protected override void OnPaint(PaintEventArgs e)
       {
            if (istoggleStatus) {
               isON();
           }
           else {
               isOFF();
           }
           base.OnPaint(e);
        }


   }



i know this need more cleaning up but it works :D this is how it looks like

http://www.computerperformance.co.uk/images/win8/pc_settings_sync.jpg[^]
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 22-Oct-12 23:47pm    
Not perfect look and code, but I like the clever and labor-saving idea of using Dock for imitation of switch position.

Well,
1) base.OnPaint is redundant in this case,
2) a setter for ColorToggleOn and all similar property setters should always call Invalidate,
3) naming isON and isOFF violates good Microsoft naming conventions and is highly misleading; good API should have just one boolean property IsOn with both setter and getter; the interface should be pretty much the same as with Check Box
4) I would avoid Designer at all and derived the control from System.Windows.Forms.ContainerControl and did all layout in code; first, it would allow you to show all your code in this answer :-) and also you would avoid cumbersome of generated code; this is one of the many cases when Designer does not help, only demands; in code, you could easily make the control more flexible.

Overall, my 4.

Cheers,
--SA
TheCardinal 23-Oct-12 1:35am    
just mock this up in a few seconds in the designer to test my concept :D
how would you do this without using the designer? i want to make this a fullblown control :D

thanks for the feedback :D
Sergey Alexandrovich Kryukov 23-Oct-12 1:59am    
If you want to support designed by control, it's yes another reason to develop it fully in code. I mean development of control, not use of it. Isn't that obvious that Designer means tedious manual development, and only code helps to do everything without repeating yourself and other stupidities? Code is more for software developer, designer is more for ad-hoc users.
--SA
Here's my quick contribution. This is a far more complete version of TheCardinal's code. This is all in code so you can add it to your project and it will show up in the designer's toolbox (no namespace - it'll be at the top). The default event is set so you can double-click the control and it will fill out a CheckChanged event handler for you. Colors, borders, and the ON/OFF label are customizable. It exposes a property called Checked just like a checkbox control.


C#
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;


//data for a change event. the current implementation
//guarantees OldValue and NewValue are always different,
//but the change event is built this way so you could change
//internal behavior if you wanted.

public class CheckChangedEventArgs : EventArgs
{
    public bool OldValue { get; set; }
    public bool NewValue { get; set; }

    public CheckChangedEventArgs(bool old_value, bool new_value)
    {
        NewValue = new_value;
        OldValue = old_value;
    }
}


//event handler
public delegate void CheckChangedEventHandler(object sender, CheckChangedEventArgs e);



[DefaultEvent("CheckChanged")]
public class ToggleSwitch : UserControl
{
    //internal variables and their defaults.
    private Color _ColorToggleOn = Color.Green;
    private Color _ColorToggleOff = Color.Red;
    private Color _ColorButtonOn = Color.Honeydew;
    private Color _ColorButtonOff = Color.Snow;
    private string _TextON = "ON";
    private string _TextOFF = "OFF";
    private bool _checked = false;
    private bool _BorderExtraThin = true;
    private bool _BorderForButton = true;
    private int _ButtonWidthPercentage = 30;

    //public properties that will show in the designer
    public Color ColorToggleOn { get { return _ColorToggleOn; } set { _ColorToggleOn = value;  UpdateColors(); } }
    public Color ColorToggleOff { get { return _ColorToggleOff; } set { _ColorToggleOff = value; UpdateColors(); } }    
    public Color ColorButtonOn { get { return _ColorButtonOn; } set { _ColorButtonOn = value; UpdateColors(); } }
    public Color ColorButtonOff { get { return _ColorButtonOff; } set { _ColorButtonOff = value; UpdateColors(); } }
    public string TextON { get { return _TextON; } set { _TextON = value; UpdateColors(); } }
    public string TextOFF { get { return _TextOFF; } set { _TextOFF = value; UpdateColors(); } }
    public bool BorderExtraThin { get { return _BorderExtraThin; } set { _BorderExtraThin = value; UpdateBorders(); UpdateColors(); Refresh(); } }
    public bool BorderForButton { get { return _BorderForButton; } set { _BorderForButton = value; UpdateBorders(); UpdateColors(); Refresh(); } }
    public int ButtonWidthPercentage { get { return _ButtonWidthPercentage; } set { _ButtonWidthPercentage = value; UpdateBorders(); UpdateColors(); Refresh(); } }

    public bool Checked
    {
        get { return _checked; }

        set
        {
            //This is set up so change events don't even occur unless the value is really changing.
            //This behavior could be modified if for some reason you want a change event without
            //  the value actually changing; which explains the CheckChangedEventArgs having a
            //  old value and a new value, even though the current implementation guarantees
            //  they are actually different.

            if (Checked == value)
                return;

            _checked = value;
            UpdateColors();

            CheckChanged(this, new CheckChangedEventArgs(!Checked, Checked));
        }
    }
    
    //we use a floating label control as the "button" and optional text.
    private Label label1;

    //CheckChanged is the default event for this control, and the only custom one we need.
    [Category("Action")]
    [Description("Fires when the switch is toggled, just like a checkbox")]
    public event CheckChangedEventHandler CheckChanged;

    void _CheckChangedDoNothing(object sender, CheckChangedEventArgs e)
    {
    }

    public ToggleSwitch()
    {
        CheckChanged = new CheckChangedEventHandler(_CheckChangedDoNothing);

        label1 = new Label();
        label1.ForeColor = this.ForeColor;
        label1.Visible = true;
        label1.TextAlign = ContentAlignment.MiddleCenter;
        label1.BorderStyle = BorderStyle.FixedSingle;
        label1.MouseDown += new MouseEventHandler(label1_MouseDown);
            
        this.Controls.Add(label1);

        UpdateColors();
    }

    void label1_MouseDown(object sender, EventArgs e)
    {
        Clicked();
    }

    protected override void OnMouseDown(MouseEventArgs e)
    {
        base.OnMouseDown(e);
        Clicked();
    }

    private void Clicked()
    {
        Checked = !Checked;
    }

    private void UpdateBorders()
    {
        if (BorderExtraThin)
        {
            BorderStyle = System.Windows.Forms.BorderStyle.None;
        }

        if (BorderForButton)
        {
            label1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
        }
    }

    private void UpdateColors()
    {
        if (Checked)
        {
            this.BackColor = ColorToggleOn;
            this.label1.Dock = DockStyle.Right;
            label1.Width = (ClientRectangle.Width * ButtonWidthPercentage) / 100;
            this.label1.Text = TextON;
            this.label1.BackColor = ColorButtonOn;

            //not sure why but it seems to need a 1-px offset to look correct
            this.label1.Padding = new Padding(1, 0, 0, 0);


            this.Refresh();
        }
        else
        {
            this.BackColor = ColorToggleOff;
            this.label1.Dock = DockStyle.Left;
            label1.Width = (ClientRectangle.Width * ButtonWidthPercentage) / 100;
            this.label1.Text = TextOFF;
            this.label1.BackColor = ColorButtonOff;

            this.Refresh();
        }
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);

        int BORDER_SIZE = 1;

        if (BorderExtraThin)
        {
            ControlPaint.DrawBorder(e.Graphics, ClientRectangle,
                Color.Black, BORDER_SIZE, ButtonBorderStyle.Inset,
                Color.Black, BORDER_SIZE, ButtonBorderStyle.Inset,
                Color.Black, BORDER_SIZE, ButtonBorderStyle.Inset,
                Color.Black, BORDER_SIZE, ButtonBorderStyle.Inset);
        }
    }
}
 
Share this answer
 
Comments
JReichert 8-Jun-15 12:04pm    
Thanks for sharing this! Jörg
I simply ended up using a customized picture box with on and off switch state images. It's a quick and dirty hack, but it works. I may eventually end up modifying it to add other images.
 
Share this answer
 

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



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900