Search code examples
c#winformsgraphicscomboboxdrawimage

ComboBox draw image on selected item


I try to draw an image from a image list in a ComboBox when the item is selected.

I am able to draw the image, but when the onSelctedIndexChanged event finish, I lost my image.

My ComboBox already have the DrawMode.OwnerDrawFixed.

I have a ListImage control named ImageList with 10 pictures.

For my short example I just need to draw in my ComboBox the image at position 1 of my ImageList, it's the reason why I get this.ImageList.Draw(g, 0, 0, **1**);

protected override void OnSelectedIndexChanged(EventArgs e)
{
    base.OnSelectedIndexChanged(e);
    
    if (this.SelectedIndex > -1)
    {
      var g = this.CreateGraphics();
      this.ImageList.Draw(g, 0, 0, 1);   
    }
}

Probably I am not subscribing to the right event. Any suggestion?

See the picture below with a breakpoint in SelectedIndexChanged after the image is drawn. It works, but I lose my image after the event.

enter image description here


Solution

  • Change your ComboBox DrawMode to OwnerDrawVariable.
    Use the DrawItem event to draw the images from your source (an ImageList, in this case) inside the ComboBox item Bounds.

    If the ComboBox DropDownStyle is set to DropDownList, the image will be shown in the selection box; if it's set to DropDown, only the text will be drawn.

    Here, the Focus rectangle is only drawn when the mouse point hovers the ListControl's items, while it's not used when an item is selected, which is determined by:
    (e.State.HasFlag(DrawItemState.Focus) && !e.State.HasFlag(DrawItemState.ComboBoxEdit)).

    private void comboBox1_DrawItem(object sender, DrawItemEventArgs e)
    {
        if (e.Index < 0) return;
        var cbo = sender as ComboBox;
        Color foreColor = e.ForeColor;
    
        if (e.State.HasFlag(DrawItemState.Selected) && !(e.State.HasFlag(DrawItemState.ComboBoxEdit))) {
            e.DrawBackground();
            e.DrawFocusRectangle(); // <= could be removed for a cleaner rendering
        }
        else {
            using (var brush = new SolidBrush(cbo.BackColor)) {
                var rect = e.Bounds;
                rect.Inflate(1, 1);
                e.Graphics.FillRectangle(brush, rect);
            }
            foreColor = cbo.ForeColor;
        }
        TextRenderer.DrawText(e.Graphics, cbo.GetItemText(cbo.Items[e.Index]), e.Font,
            new Point(e.Bounds.Height + 10, e.Bounds.Y), foreColor);
    
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        e.Graphics.DrawImage(imageList1.Images[e.Index],
                             new Rectangle(e.Bounds.Location,
                             new Size(e.Bounds.Height - 2, e.Bounds.Height - 2)));
    }
    

    The Magic Numbers here (10, -2) are just offsets:
    e.Bounds.Height + 10 => 10 pixels to the right of the image.
    e.Bounds.Height -2 => 2 pixels less than the item.Bounds.Height.

    ComboBox Ownerdraw with Images