VB.Net (winforms) - StarRatingControl
Overview
This is a graphical Custom Control that extends the available ToolBox items in VB.Net.
Fortunately it is very easy to create, compile, and distribute your own Custom Controls these days.
How-To
This is a Custom Control that was written as a tutorial for those interested in writing their own Controls. It started out with a standard winforms application (the demo application).
From the File menu, choose Add-->New Project, then from the Dialog that appears, choose and name, a Class Library project (which provides you with an empty Class template - Class1). This adds a suitable project to the solution. This project will contain the StarRatingControl.
You could also choose a Windows Forms Control Library project (which provides you with an empty UserControl template - UserControl1).
In this case the Class Library was utilized, deleting the default Class1, then adding a new UserControl, naming it StarRatingControl.
The StarRatingControl is composed of a UserControl, containing five PictureBoxes and one Label. The PictureBoxes contain (at runtime) either a grey star, a gold star, or a part grey, part gold star.
There are three UserControl views -
live
This view is when the user moves the mouse over the Control.
clicked
This view is when the user has clicked one of the UserControl PictureBoxes whilst in live view. In this view the UserControl remains frozen until the user moves the mouse outside of the UserControl.
average
This view is where the stars display a graphical average of all ratings, and the label displays a textual average.
This is the view that displays when the user moves the mouse outside of the UserControl.
The StarRatingControl code
The code is simple, handling the MouseMove and MouseDown events for the PictureBoxes, and the MouseLeave event for the UserControl and all of the contained Controls. This is to facilitate changing the currentView variable to allow using the UserControl as an input Control, and also as a display Control.
Imports System.ComponentModel
<ToolboxBitmap(GetType(StarRatingControl), "star16x16.png")> _
Public Class StarRatingControl
Private pictureboxes() As PictureBox
Private Enum ControlView
live
clicked
average
End Enum
Private currentView As ControlView = ControlView.live
Private rating As Integer = -1
Private ratings As New List(Of Integer)
''' <summary>
''' Default Constructor
''' </summary>
''' <remarks>Sets up class level array and PictureBox EventHandlers</remarks>
Public Sub New()
' This call is required by the Windows Form Designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
pictureboxes = New PictureBox() {PictureBox1, PictureBox2, PictureBox3, PictureBox4, PictureBox5}
For Each pb As PictureBox In pictureboxes
AddHandler pb.MouseMove, AddressOf pb_MouseMove
AddHandler pb.MouseDown, AddressOf pb_MouseDown
AddHandler pb.MouseLeave, AddressOf pb_MouseLeave
Next
ratings.Add(0)
End Sub
#Region " selection handlers"
Private Sub pb_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
Dim pb As PictureBox = DirectCast(sender, PictureBox)
If currentView = ControlView.live Then
Dim i As Integer = Array.IndexOf(pictureboxes, pb)
For x As Integer = 0 To 4
If x <= i Then
pictureboxes(x).Image = My.Resources.star_512
Else
pictureboxes(x).Image = My.Resources.star_512_grey
End If
Next
ElseIf currentView = ControlView.average Then
currentView = ControlView.live
End If
End Sub
Private Sub pb_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
Dim pb As PictureBox = DirectCast(sender, PictureBox)
If currentView = ControlView.live Then
If e.Button = Windows.Forms.MouseButtons.Left Then
Dim i As Integer = Array.IndexOf(pictureboxes, pb)
rating = i
ratings(ratings.Count - 1) = rating + 1
ratings.Add(0)
currentView = ControlView.clicked
End If
changeStars()
End If
End Sub
#End Region
#Region " mouseleave handlers"
Private Sub StarRatingControl_MouseLeave(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.MouseLeave
If Not Me.Bounds.Contains(Me.ParentForm.PointToClient(MousePosition)) Then
currentView = ControlView.average
changeStars()
End If
End Sub
Private Sub Label1_MouseLeave(ByVal sender As Object, ByVal e As System.EventArgs) Handles Label1.MouseLeave
StarRatingControl_MouseLeave(sender, e)
End Sub
Private Sub pb_MouseLeave(ByVal sender As Object, ByVal e As EventArgs)
StarRatingControl_MouseLeave(sender, e)
End Sub
#End Region
''' <summary>
''' changeStars method
''' </summary>
''' <remarks>Handles display for fixed control views</remarks>
Private Sub changeStars()
If currentView = ControlView.clicked Then
For x As Integer = 0 To 4
If x <= rating Then
pictureboxes(x).Image = My.Resources.star_512
Else
pictureboxes(x).Image = My.Resources.star_512_grey
End If
Next
Label1.Text = String.Format("Average {0:n2} over {1} ratings", ratings.Sum / (ratings.Count - 1), ratings.Count - 1)
ElseIf currentView = ControlView.average Then
If ratings.Count = 1 Then
Label1.Text = "No ratings yet"
For x As Integer = 0 To 4
pictureboxes(x).Image = My.Resources.star_512_grey
Next
Return
End If
Dim i As Integer = CInt(Math.Floor(ratings.Sum / (ratings.Count - 1))) - 1
For x As Integer = 0 To 4
If x <= i Then
pictureboxes(x).Image = My.Resources.star_512
Else
pictureboxes(x).Image = My.Resources.star_512_grey
End If
Next
If i < 4 AndAlso (ratings.Sum / (ratings.Count - 1) - (i + 1)) <> 0 Then
Dim img1 As Bitmap = My.Resources.star_512
Dim img2 As Bitmap = My.Resources.star_512_grey
Dim gr As Graphics = Graphics.FromImage(img2)
Dim r As Rectangle = New Rectangle(0, 0, CInt(Math.Round((ratings.Sum / (ratings.Count - 1) - (i + 1)) * 25)), 25)
gr.DrawImage(img1, r, r, GraphicsUnit.Pixel)
pictureboxes((i + 1)).Image = img2
End If
Label1.Text = String.Format("Average {0:n2} over {1} ratings", ratings.Sum / (ratings.Count - 1), ratings.Count - 1)
End If
End Sub
End Class
Adding a ToolBoxBitmap
Finally, as this is a Control that can be added to your ToolBox in it's compiled state, a 16x16 image was added to the UserControl project, and set as an Embedded Resource. To use the image as the icon shown in the ToolBox, a ToolboxBitmap Attribute was added to the top of the StarRatingControl code.
Conclusion
This is a simple example that shows how a versatile, reusable, and distributable Custom Control can be made easily in VB.Net