WEBINAR: On-demand webcast
How to Boost Database Development Productivity on Linux, Docker, and Kubernetes with Microsoft SQL Server 2017 REGISTER >
I have always loved playing around with controls to push them to their limits. Today is no exception. This article will provide you with enough background to be able to use the Owner draw methods to add more spice to your controls.
Owner Drawing: What Is It?
Owner drawing in Windows Forms, which is also known as custom drawing, is a technique for changing the visual appearance of certain controls. Here is more information: https://msdn.microsoft.com/en-us/library/yyfab68k%28v=vs.110%29.aspx.
The MeasureItem Event
The DrawItem Event
You can use this event to perform the tasks needed to draw items in the ComboBox. If you have a variable sized item (when the ComboBox.DrawMode property is set to the OwnerDrawVariable value of System.Windows.Forms.DrawMode), before drawing an item, the MeasureItem event is raised. You can create an event handler for the MeasureItem event to specify the size for the item that you are going to draw in your event handler for the DrawItem event. Here is more information: https://msdn.microsoft.com/en-us/library/system.windows.forms.combobox.drawitem%28v=vs.110%29.aspx.
Today's Practical Exercise
Start Visual Studio and create a new Visual Basic Windows Forms project. You may name it anything you like; you may also name all the objects on each form anything you like. Keep in mind, though, that your naming convention may be different than mine, so our object names might not be the same.
Design Form 1 to resemble Figure 1:
Figure 1: Form 1 Design
Remember to add an Imagelist to Form 1 as well and add a few images to it. Design Form 2 to resemble Figure 2:
Figure 2: Form 2 Design
Set the OwnerDraw Property for the Listbox to OwnerDrawVariable.
Create a Hashtable to store the list items:
Private htListItems As New Hashtable
This will host all our list items for the combobox.
Override the Form's Onload event:
Protected Overrides Sub OnLoad(ByVal e As _ System.EventArgs) MyBase.OnLoad(e) With Me.ImageList1.Images .Add(SystemIcons.Application) Me.htListItems.Add(0, "This is the " & _ Environment.NewLine & "Application Icon") .Add(SystemIcons.Asterisk) Me.htListItems.Add(1, "This is the " & _ Environment.NewLine & "Asterisk Icon") .Add(SystemIcons.Error) Me.htListItems.Add(2, "This is the " & _ Environment.NewLine & "Error Icon") .Add(SystemIcons.Exclamation) End With End Sub
This simply loads all the items into the Hashtable. For more information regarding Overriding, read here.
Add the Form Load event:
Private Sub Form1_Load(sender As Object, _ e As EventArgs) Handles Me.Load Me.ComboBox1.Items.Clear() Me.ComboBox1.Text = "" Dim i As Integer Dim s As String For i = 0 To 2 s = Join(Split(Me.htListItems(i), _ Environment.NewLine), "") Me.ComboBox1.Items.Add(s) Next i End Sub
Inside this event, the list items are added to the Combobox, using the Split and Join string functions. For more information regarding Split and Join, please read here.
Add the Combobox's MeasureItem event:
Private Sub ComboBox1_MeasureItem(ByVal sender As Object, _ ByVal e As System.Windows.Forms.MeasureItemEventArgs) _ Handles ComboBox1.MeasureItem If e.Index < 0 Then Return Dim str As String = Me.htListItems(e.Index) Dim strOneLine As String = _ Join(Split(str, Environment.NewLine), "") Dim img As Image = Me.ImageList1.Images(e.Index) Dim hgt As Single = Math.Max(img.Height, _ e.Graphics.MeasureString(str, Me.ComboBox1.Font).Height) _ * 1.1 e.ItemHeight = hgt If Me.ComboBox1.DropDownStyle = ComboBoxStyle.DropDownList Then Me.ComboBox1.ItemHeight = hgt Else Me.ComboBox1.ItemHeight = _ e.Graphics.MeasureString(strOneLine, _ Me.ComboBox1.Font).Height * 1.1 End If e.ItemWidth = Me.ComboBox1.Width End Sub
This event simply calculates the height of the picture (that was added earlier) along with the height of the text which also was added earlier, and ensures that the display renders it correctly depending on the different Combobox styles.
Add the DrawItem event:
Private Sub ComboBox1_DrawItem(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DrawItemEventArgs) _ Handles ComboBox1.DrawItem If e.Index < 0 Then Return Dim str As String = Me.htListItems(e.Index) Dim g As Graphics = e.Graphics Dim bBlue As SolidBrush = New SolidBrush(Color.Blue) Dim bWhite As SolidBrush = New SolidBrush(Color.White) Dim hgt As Single Dim img As Image = Me.ImageList1.Images(e.Index) If Me.ComboBox1.DrawMode = DrawMode.OwnerDrawFixed Then hgt = Math.Max(img.Height, _ e.Graphics.MeasureString(str, _ Me.ComboBox1.Font).Height) _ * 1.1 Me.ComboBox1.ItemHeight = hgt End If bBlue.Dispose() bWhite.Dispose() bBlue = Nothing bWhite = Nothing End Sub
This event simply draws the desired items into the ComboBox.
Load the items into the ListBox:
Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load ListBox1.Items.Add("One") ListBox1.Items.Add("Two") ListBox1.Items.Add("Three") End Sub
This is self-explanatory, but if you're unfamiliar with the concept, the preceding code simply loads items into a ListBox.
Add the DrawItem event:
Private Sub ListBox1_DrawItem(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DrawItemEventArgs) _ Handles ListBox1.DrawItem Dim textFont As Font textFont = New Font(e.Font.FontFamily, e.Font.Size * 2) e.Graphics.DrawString(ListBox1.Items(e.Index).ToString(), _ textFont, _ New SolidBrush(e.ForeColor), _ e.Bounds.X, e.Bounds.Y) e.DrawFocusRectangle() End Sub
In the previous DrawItem event, you created a new Font object and set the font object's size to double than the previous size. Lastly, the DrawString Graphics method is used to draw the Listbox item with the new font.
Ownerdrawing controls can be easy and fun. Enjoy playing around with them