You want to provide custom drawing code for a control.
Sample code folder: Chapter 04\ControlDrawing
For most controls, provide an event handler for the Paint event, and add your drawing code there. This event's second argument includes a Graphics property representing the canvas on which you can issue your drawing commands. Some controls also provide separate DrawItem events that let you draw specific portions of the control, such as distinct items in a ListBox control. You can also draw directly on the form's surface. This recipe's code includes samples for all these activities.
Create a new Windows Forms application, and add two controls: a Button control named XButton and a ComboBox control named ColorList. Change the ColorList control's DrawMode property to OwnerDrawFixed and its DropDownStyle property to DropDownList. Then add the following source code to the form's code template:
Private Sub Form1_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load ' ----- Add some basic colors to the color list. ColorList.Items.Add("Red") ColorList.Items.Add("Orange") ColorList.Items.Add("Yellow") ColorList.Items.Add("Green") ColorList.Items.Add("Blue") ColorList.Items.Add("Indigo") ColorList.Items.Add("Violet") End Sub Private Sub Form1_Paint(ByVal sender As Object, _ ByVal e As System.Windows.Forms.PaintEventArgs) _ Handles Me.Paint ' ----- Draw an ellipse on the form. e.Graphics.DrawEllipse(Pens.Black, 10, 10, _ Me.ClientRectangle.Width - 20, _ Me.ClientRectangle.Height - 20) End Sub Private Sub XButton_Paint(ByVal sender As Object, _ ByVal e As System.Windows.Forms.PaintEventArgs) _ Handles XButton.Paint ' ----- Draw a big x in a rectangle on the button surface. Dim usePen As Pen ' ----- Provide a neutral background. e.Graphics.Clear(SystemColors.Control) ' ----- Draw the outline box. usePen = New Pen(SystemColors.ControlText, 3) e.Graphics.DrawRectangle(usePen, XButton.ClientRectangle) ' ----- Draw the x. e.Graphics.DrawLine(usePen, 0, 0, _ XButton.Width, XButton.Height) e.Graphics.DrawLine(usePen, 0, _ XButton.Height, XButton.Width, 0) usePen.Dispose( ) End Sub Private Sub ColorList_DrawItem(ByVal sendesender As Object, _ ByVal e As System.Windows.Forms.DrawItemEventArgs) _ Handles ColorList.DrawItem ' ----- Draw the color instead of the text. Dim useBrush As Brush ' ----- Check for a nonselected item. If (e.Index = -1) Then Return ' ----- Set the neutral background. e.DrawBackground( ) ' ----- Fill in the color. useBrush = New SolidBrush(Color.FromName(CStr( _ ColorList.Items(e.Index)))) e.Graphics.FillRectangle(useBrush, _ e.Bounds.Left + 2, e.Bounds.Top + 2, _ e.Bounds.Width - 4, e.Bounds.Height - 4) useBrush.Dispose( ) ' ----- Surround the color with a black rectangle. e.Graphics.DrawRectangle(Pens.Black, _ e.Bounds.Left + 2, e.Bounds.Top + 2, _ e.Bounds.Width - 4, e.Bounds.Height - 4) ' ----- Show the item selected if needed. e.DrawFocusRectangle( ) End Sub Private Sub XButton_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles XButton.Click MsgBox("Button clicked.") End Sub
Run the program. The XButton control no longer looks like a button; it instead looks like a custom-drawn "X." Although the button looks strange, it still works. The ellipse we drew directly on the form's surface is there. Also, the ComboBox control now displays actual colors instead of just the names of colors. This all appears in Figure 4-4.
Figure 4-4. Controls drawn with custom code
Some of the controls that support item-level drawing, such as the ListBox and ComboBox controls, include an e.State property in the data passed to the event handler. This value indicates the current state of the item being drawn:selected, not selected, or a half dozen other relevant states. You do not need to take that property into account if your implementation doesn't require it, but it is generally a good idea to provide feedback to the user in a way the user expects. Adjusting the display based on this property helps achieve that purpose.
As shown in the sample code, the DrawItem event handler includes e.DrawBackground() and e.DrawFocusRectangle() methods that help you properly draw the item. Availability of these methods varies by control type.
See the recipes in Chapter 9 for examples that use the various GDI+ drawing commands.