0

I'm adding a control to a picturebox. This control is a component, precisely it's a toggle switch posted here. I'd like this control to be vertical and not horizontal .

So, since objects can't be rotated or flipped, I found a way to flip the picturebox image with:

PictureBox1.Image.RotateFlip(RotateFlipType.Rotate180FlipNone)
    PictureBox1.Refresh()

The error I'm getting at RunTime is:

System.Windows.Forms.PictureBox.Image.get returned Nothing

Endeed the control is not an image so is there a way to flip the control inside of the picturebox by 180 degrees? Also, You think there is a way to know when the value of the toggle switch is on or off? Thanks

Mattia
  • 258
  • 7
  • 25
  • 1
    If you want it to be vertical, don't you mean "rotate by 90 degrees"? Anyway, what you're doing here is valid for a bitmap, but you're dealing with a control. Just because it's in a PictureBox doesn't mean it's an image. You can't just rotate it, you just need to paint it differently in the `OnPaint` method (i.e., using a different path). – 41686d6564 stands w. Palestine Oct 07 '20 at 02:24
  • 1
    A control draws itself. For that switch to be displayed vertically, there would have to be code inside that control to draw it vertically. In that context, you would generally add a property to control the orientation and then read that property inside the `OnPaint` method and draw appropriate. You need to understand that drawing code and determine how to modify it to draw the way you want. – jmcilhinney Oct 07 '20 at 02:37
  • 1
    *"You think there is a way to know when the value of the toggle switch is on or off"*. Well that just shows that you've not made an effort to understand the code. It's a custom `CheckBox` control. Do you really not know how to use a `CheckBox`? It's even in the drawing code. – jmcilhinney Oct 07 '20 at 02:38
  • 1
    Just for curiosity purposes, It would be possible to "convert" what picturebox is displaying ( eventhough is a control or whatever )to an image? – Mattia Oct 07 '20 at 08:25

1 Answers1

2

As already mentioned above, extend the control to have it drawn either horizontally or vertically.

Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms

Public Class ToggleSwitch
    Inherits CheckBox

    Public Sub New()
        MyBase.New

        SetStyle(ControlStyles.AllPaintingInWmPaint Or
                 ControlStyles.UserPaint, True)
        UpdateStyles()
        Padding = New Padding(6)
    End Sub

    Private _orientation As Orientation = Orientation.Horizontal
    Public Property Orientation As Orientation
        Get
            Return _orientation
        End Get
        Set(value As Orientation)
            _orientation = value

            Dim max = Math.Max(Width, Height)
            Dim min = Math.Min(Width, Height)

            If value = Orientation.Vertical Then
                Size = New Size(min, max)
            Else
                Size = New Size(max, min)
            End If
        End Set
    End Property

    'Fix by: @41686d6564
    <Browsable(False),
    Bindable(False),
    DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
    EditorBrowsable(EditorBrowsableState.Never)>
    Public Overrides Property AutoSize As Boolean
        Get
            Return False
        End Get
        Set(value As Boolean)
        End Set
    End Property

    Protected Overrides Sub OnPaint(e As PaintEventArgs)
        Dim g = e.Graphics

        g.Clear(BackColor)
        g.SmoothingMode = SmoothingMode.AntiAlias
        g.PixelOffsetMode = PixelOffsetMode.Half

        Dim p = Padding.All
        Dim r = 0
        Dim rec As Rectangle

        Using gp = New GraphicsPath
            If _orientation = Orientation.Vertical Then
                r = Width - 2 * p
                gp.AddArc(p, p, r, r, -180, 180)
                gp.AddArc(p, Height - r - p, r, r, 0, 180)
                r = Width - 1
                rec = New Rectangle(0, If(Checked, Height - r - 1, 0), r, r)
                'Or
                'rec = New Rectangle(0, If(Checked, 0, Height - r - 1), r, r)
                'To get the ON on top.
            Else
                r = Height - 2 * p
                gp.AddArc(p, p, r, r, 90, 180)
                gp.AddArc(Width - r - p, p, r, r, -90, 180)
                r = Height - 1
                rec = New Rectangle(If(Checked, Width - r - 1, 0), 0, r, r)
            End If

            gp.CloseFigure()

            g.FillPath(If(Checked, Brushes.DarkGray, Brushes.LightGray), gp)
            g.FillEllipse(If(Checked, Brushes.Green, Brushes.WhiteSmoke), rec)
        End Using
    End Sub

End Class

SOQ64236248

As for the second part of your question, please read CheckBox.Checked property and CheckBox.CheckedChanged event.

Impelemntation example:

Private Sub ToggleSwitch1_CheckedChanged(sender As Object, e As EventArgs) Handles ToggleSwitch1.CheckedChanged
    If ToggleSwitch1.Checked Then
        'ToDo with ON state...
    Else
        'ToDo with OFF state..
    End If
End Sub
dr.null
  • 4,032
  • 3
  • 9
  • 12
  • That's perfect, thanks . Just a simple question. If I want to switch on towards up, what should i change? – Mattia Oct 07 '20 at 10:37
  • @Mattia You are welcome. Just toggle the `Checked` property. Like: `ToggleSwitch1.Checked = True` – dr.null Oct 07 '20 at 11:55
  • Hi dr.null, I don't mean that. As you can see, you are switching on the toggle moving it down, While I'm asking how to make it the opposite way. – Mattia Oct 07 '20 at 12:01
  • 1
    @Mattia ah I see. It makes more sense your way. In the vertical painting, just replace the line `rec = New Rectangle(0, If(Checked, Height - r - 1, 0), r, r)` with `rec = New Rectangle(0, If(Checked, 0, Height - r - 1), r, r)`. I added that commented in the code. – dr.null Oct 07 '20 at 12:08
  • 1
    Oh thanks that s exactly what I was looking for. I appreciated your help. – Mattia Oct 07 '20 at 12:16
  • 1
    Nice work. Upvoted. There's one issue though: changing the value of `AutoSize` in the constructor will have no effect on instances added at design-time. To get around this, you may decorate the class with `` as explained [here](https://stackoverflow.com/a/48353592/8967612). – 41686d6564 stands w. Palestine Oct 07 '20 at 21:23
  • 1
    A better approach would be to override the `AutoSize` property. Then, you have two options. Option 1) Make it always return false and hide it from the designer and IntelliSense (by decorating it with ``, ``, ``, and ``). Option 2) Implement your own autosizing logic in the property's setter. – 41686d6564 stands w. Palestine Oct 07 '20 at 21:23