1. Introduction To C# Owner Drawn Control
When the container draws the control, we call it as an Owner Drawn Control. First, let us study the default behavior. When we place a control on the form, the control’s appearance is decided by the control itself. Let us say, for example, that we placed a Combo Box control on the form. The dot-net framework takes care of the ComboBox appearance. Means, the ComboBox class or its parent class can take the responsibility of drawing the control. This involves drawing a white rectangle for a text box followed by a small square with a down arrow in it. When the user clicks the down arrow, the control draws one more rectangle below combo box to show the list of items.
The control drawing itself is a normal behavior. Now, let us say that the Form draws each ComboBox item with a double lined red border around each item. Here, the Form is called a Parent or Owner of the ComboBox and the control is known as ‘Owner Drawn Control’. In easy words, the Form (Owner of the ComboBox) draws the ComboBox Items. In this article, we will see how to create an Owner Drawn ComboBox with color titles along with text.
2. About The Example
Below is the Screenshot of the application that we will create:
In the above screenshot, we change the default appearance of the ComboBox to display the color boxes. This ComboBox is partly drawn by the Form. That is, the class for the ComboBox control draws the ComboBox with a Down Arrow. In our example, the Form draws the content of the ComboBox when it is dropped down.
The Owner of the ComboBox in this example will perform the Following drawing:
- Color Rectangle.
- Text String next to the color rectangle.
- Red Border around the selected Item.
Once the color is selected from this Owner Drawn ComboBox, the text typed in the text box will appear in the selected color.
3. The DrawMode Property
Some controls like ListBox, ComboBox, Tab and TreeView Control supports Owner Draw. All these controls have the property called ‘DrawMode’, which specifies what kind of owner drawn will be used. The ComboBox and ListBox supports three kinds of DrawMode, and these modes are:
- Normal
- OwnerDrawFixed
- OwnerDrawVariable
3.1 Normal Mode
Normal Mode is the default drawing mode set to a ListBox and ComboBox control. In this Mode, the control class takes the responsibility of drawing itself and drawing each item in it.
3.2 OwnerDrawFixed Mode
When we set OwnerDrawFixed Mode to the DrawMode property, the owner will draw the control by handling the ‘DrawItem Event’. Each item will have fixed height.
3.3 OwnerDrawVarible Mode
In OwnerDrawVarible Mode, the owner will draw and measure each item. So, we can say that each item can have various heights. When this Mode is set, the owner of the control should add handlers for the ‘DrawItem’ and ‘MeasureItem’ events. In the MeasureItem Handler, we measure each item and in the DrawItem, we draw each item. The Dot-Net framework calls the MeasureItem Handler only during the control initialization. But Dot.Net will call the DrawItem Handler for each item whenever the user clicks the drop arrow button.
For our Owner Drawn ComboBox example, we need to set the OwnerDrawFixed to the DrawMode property as shown below:
4. Preparing The Example
4.1 Text Strings Of Owner Drawn ComboBox
In the Form Load handler function, we populate the combo box with the strings that represent the color. We will draw our color tiles before this string of texts. Below is the code:
1 2 3 4 5 6 7 8 9 10 11 |
//Snippet 02: Populate the Owner Drawn Combo box private void frmComboSample_Load(object sender, EventArgs e) { OwnerDCombo.Items.Add("Red"); OwnerDCombo.Items.Add("Blue"); OwnerDCombo.Items.Add("Green"); OwnerDCombo.Items.Add("Chocolate"); OwnerDCombo.Items.Add("Gold"); OwnerDCombo.Items.Add("Purple"); OwnerDCombo.Items.Add("LigntSeaGreen"); } |
4.2 Function to Return Color Instance
Next, write a function that returns the ‘
System.Drawing.Colour
’. The function takes a standard color name in string format and returns the
Color
instance. Below is the function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
//Snippet 03: Get the Colour selected in the Combo box public Color GetColor(String ColorName) { Color col = Color.Black; if (ColorName == "Red") { col = Color.Red; } else if(ColorName == "Blue") { col = Color.Blue; } else if(ColorName == "Green") { col = Color.Green; } else if(ColorName == "Chocolate") { col = Color.Chocolate; } else if(ColorName == "Gold") { col = Color.Gold; } else if (ColorName == "Purple") { col = Color.Purple; } else { col = Color.LightSeaGreen; } return col; } |
4.3 Retrieve Color Of User Choice
In the ComboBox Selection change, we get the selected colour to set the ‘ForeColor Property’ of the text box. To retrieve the colour, we use the previously written GetColor() function. Below is the code for that:
1 2 3 4 5 6 7 8 9 10 11 |
//Snippet 03: Set the Textbox colour based on the Combo Selection private void OwnerDCombo_SelectedIndexChanged(object sender, EventArgs e) { if (OwnerDCombo.SelectedIndex == -1) return; String strColor = (String)OwnerDCombo.Items[OwnerDCombo.SelectedIndex]; TxtNotePad.ForeColor = GetColor(strColor); } |
5. Owner Drawn ComboBox With Color Tiles & Text
5.1 DrawItem Handler Of ComboBox
As already pointed out, in our ComboBox the
DrawItem Handler
will do the drawing for each item present in the Combo. The dot-net framework will call this DrawItem Handler when user click the down arrow. If there are ‘n’ elements, dot-net calls this handler function ‘n’ times. This happens when DrawMode is not Normal. In this DrawItem Handler, first, we get the Color Object and colour name by making use of the index revealed by the ‘
DrawItemEventArgs
’.
1 2 3 4 5 6 7 |
private void OwnerDCombo_DrawItem(object sender, DrawItemEventArgs e) { //Snippet 04.1: Get the color currently selected in the Combobox String strColor = (String) OwnerDCombo.Items[e.Index]; Color Selected_Color = GetColor(strColor); String color_name = Selected_Color.Name; |
5.2 Erase Background Using DrawItemEventArgs
As the DrawItem function takes the duty of drawing the content of each combo box item, it first performs the background drawing. So, we get
Graphics
object
grp
from the
DrawItemEventArgs
then call
DrawBackGround()
function from the same
DrawItemEventArgs
. This will clear all the previous drawing in the drop-down list. Below is the code:
1 2 3 |
//Snippet 04.2: Get the Graphics from the Argument Graphics grp = e.Graphics; e.DrawBackground(); |
5.3 DrawItemEventArgs & Item Bounds
The
DrawItemEventArgs
supplies bounding box of the current combo box item through its member
Bounds
. First, we apply a one-pixel indent on Top, Left and Bottom using the
Bounds
of
DrawItemEventArgs
. And we fix the width as 20 pixels. Based on this
Bounds
, a
Rectangle
rct
is formed. Through the already retrieved
Graphics
object, we draw the rectangle tile for the current combo box item. Note, the Framework calls this
DrawItem Handler
for every item and we get the
Bounds
of each item via the
DrawItemEventArgs
. Below is the code:
1 2 3 4 5 6 7 8 9 |
//Snippet 04.3: Get the bounding rectangle to draw the item int Rect_left = e.Bounds.X + 1; int Rect_top = e.Bounds.Y + 1; Rectangle rct = new Rectangle( Rect_left, Rect_top, 20, e.Bounds.Height - 2); grp.DrawRectangle(Pens.Black, rct); |
When we run our Owner Drawn ComboBox at this stage, it looks like as shown below:
5.4 Painting Rectangle Tiles
After forming the rectangle tile, we fill it with the needed color that matches with the item string. To perform the paint operation on the rectangle, we create a
GDI+ Brush
object. Note, The brush color matches to the text string of the ComboBox item. Below is code for filling the rectangle using GDI+ brush:
1 2 3 |
//Snippet 04.4: Create a Solid Brush and Fill the Item Rectangles SolidBrush brush = new SolidBrush(Selected_Color); grp.FillRectangle(brush, rct); |
Now the Owner Drawn ComboBox looks like below now:
5.5 Calculate Left Offset & Draw String
Now we have colour rectangles in the combo box. Next, we should add the text that belongs to the colour rectangle. To draw the text, we should have offset from the left of the combo box as the rectangle is already occupying the left portion. To apply offset for drawing the text, we should perform the summation of, left offset already done to draw the rectangle (Shown as 1), the rectangle width and the new offset from the right of the colour rectangle which we will hard code it as 2 pixels. The summation will give the starting location of the text from the left side of drop-down list. Below picture explains this:
In the code, we make a call to
DrawString()
method on the retrieved
grp
object. While calling the function, the left location of the string to be drawn is calculated based on the color rectangle’s dimensions, which we already explored. Below is the code that draws the text next to the color Rectangle:
1 2 3 4 5 6 7 |
//Snippet 04.5: Create a Brush for drawing the texts SolidBrush textb = new SolidBrush(Color.Black); grp.DrawString(color_name, e.Font, textb, Rect_left + rct.Width + 2, Rect_top); |
Running the Owner Drawn ComboBox at this stage look like below.
5.6 Drawing Bounding Rectangle For Highlighting
At last, we draw a bounding rectangle for the selected combo box item. By performing Bit-wise AND (&) with ‘
e.state
’. The state can tell that the current item we are drawing is in selected stated or Not. When an item is in Highlighted state, we draw a bounding rectangle around it in the Red Rectangle colour. To erase previously drawn red bounding rectangle, we perform the drawing in the else portion. One can see this bounding rectangle when they move the selection using mouse & up/down arrow keys. Below is the code:
1 2 3 4 5 6 7 8 9 |
//Snippet 04.6: Draw a Border around the Selected Item if ((DrawItemState.Selected & e.State) == DrawItemState.Selected) { grp.DrawRectangle(Pens.Red, e.Bounds); } else { grp.DrawRectangle(Pens.White, e.Bounds); } |
The below given video shows the completed Owner Drawn ComboBox Example:
Video: Running the Owner Drawn Example
Source Code: Download C# Owner Drawn ComboBox Example From Google Drive
Categories: C#
Tags: DrawItem Handler, DrawItemEventArgs, DrawItemEventArgs.Bounds, DrawItemEventArgs.State, DrawItemState, DrawMode Propety
hi thanks for your example!
But can you update the Source Code download link, it can’t download.
Thanks!
Download Link updated. Thanks for pointing out!
thanks!!!
Can we use ComboBoxEx control ?…
https://docs.microsoft.com/en-us/windows/win32/controls/how-to-prepare-comboboxex-items-and-images