2

I'm trying to paint an image inside Combobox in a custom control, I use the following code:

    public partial class Jo_ComboBox : ComboBox
{


    #region Constructor

    public Jo_ComboBox()
    {
        InitializeComponent();
        
    }

    #endregion

    #region Fields

    bool _IsRequired = false;
    bool _IsEmpty = true;
    Bitmap _xImg;

    #endregion


    #region Properties

    [Category("Joul_Properties")]
    public Bitmap xImg { get { return _xImg; } }

    [Category("Joul_Properties")]
    public bool IsEmpty { get { return _IsEmpty; } }

    [Category("Joul_Properties")]
    public bool IsRequired { get { return _IsRequired; } set { _IsRequired = value; } }

    #endregion


    protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
    {
        base.OnPaint(e);

        if (IsRequired == true && this.Text == string.Empty)
        {
            _xImg = Resources._16Exc;
            e.Graphics.DrawImage(xImg, new Point(this.Width - 18, 30));
            _IsEmpty = true;
        }
        else
        {
            _IsEmpty = false;
        }




    }


    #region Events 

   
    //OnLeave
    protected override void OnLeave(EventArgs e)
    {
        base.OnLeave(e);
        this.Invalidate();
    }

    #endregion

actually, I got a good result but I noticed that the image is not above the textbox of the Combobox, I noticed that when I tried to change the hight of combobox.

enter image description here

see the video please to know what is the problem:

enter link description here

edit: please see that there is editor area that is covering the image if I change the height

enter image description here

M.J
  • 143
  • 9
  • https://stackoverflow.com/a/50103139/14171304 – dr.null Jan 29 '22 at 06:59
  • @dr.null thanks, I already saw that solution but I couldn't apply it, actually, I'm using custom control so I tried but I couldn't, I don't want the image with items I just need it on the text line – M.J Jan 29 '22 at 08:54
  • ah, I see. In case you need to center the image vertically: `e.Graphics.DrawImage(_xImg, Width - _xImg.Width - 3, (Height - _xImg.Height) / 2);` – dr.null Jan 29 '22 at 14:21
  • @dr.null sorry but still the same problem please see the video in the link in the post – M.J Jan 29 '22 at 15:19
  • @dr.null there is a link in last of the post contains a video explains my problem – M.J Jan 29 '22 at 15:26
  • The posted code has nothing to do with what's in the video. Please post the relevant code. For now, if the drawing canvas is a `UserControl`, then you should handle the `UserControl.Paint` event not the `ComboBox's`. Maybe clarifying what you are after helps someone to give you some alternatives. – dr.null Jan 29 '22 at 18:03
  • @dr.null sorry, but it's the relevant code and I applied it on UserControl.Paint but I got the same result, the problem is I noticed that there is a rectangle is covering the area, I think that rectangle is the editor area so we are paining on the background but the problem is how to paint on the editor area – M.J Jan 30 '22 at 06:28
  • @dr.null I added an image to the post to explain the editor area – M.J Jan 30 '22 at 06:35
  • No it is not :) Can't reproduce the problem with this code. .. 1) The posted code as is does not fire the `OnPain`. 2) `InitializeComponent();` in a custom `ComboBox` ctor does not make sense. 3) The video shows docking and/or resizing the ComboBox and nothing here explains how. 4) Nothing mentioned about the ComboBox properties, `DrawMode`, `DropDownStyle`, and maybe `ItemHeight`. 5) What's the purpose of using a `UserControl` to create a custom `ComboBox`? Posting the relevant code answers all of that. – dr.null Jan 30 '22 at 11:18
  • @dr.null thanks for your patience, actually, it's the first time I make user control so some of the things that you mentioned I don't know that is mean exactly, could you please give me a link to explain or if you can help me by making a custom Combobox to see how to make it correctly. – M.J Jan 30 '22 at 18:56
  • No problem. Your are welcome. See [this](https://stackoverflow.com/a/65513056/14171304) and [this](https://stackoverflow.com/a/49820008/14171304). Also, what do you need from a custom `ComboBox`? just to draw that image? To increase the `Height`? If you could edit your post to include what do you need in 1, 2, 3 list. – dr.null Jan 31 '22 at 11:58
  • Just in case, Consider [Using Error Provider Control in Windows Forms and C#](https://www.c-sharpcorner.com/article/using-error-provider-control-in-windows-forms-and-C-Sharp/). and [Here's](https://stackoverflow.com/a/65966553/14171304) another example. – dr.null Jan 31 '22 at 12:24
  • @dr.null thank you so much – M.J Jan 31 '22 at 19:12

1 Answers1

2

thank you @dr.null

I applied the following code and it's working:

    using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class MyComboBox : ComboBox
{
    public MyComboBox()
    {
        SetStyle(ControlStyles.ResizeRedraw, true);
        DrawMode = DrawMode.OwnerDrawFixed;
        ItemHeight = 40;
}

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;
    public int Width { get { return Right - Left; } }
    public int Height { get { return Bottom - Top; } }
}

private const int SWP_NOSIZE = 0x0001;
private const int SWP_NOZORDER = 0x0004;
private const int SWP_SHOWWINDOW = 0x0040;
[DllImport("user32.dll", SetLastError = true)]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, 
    int X, int Y, int cx, int cy, int uFlags);

[DllImport("user32.dll")]
public static extern bool GetComboBoxInfo(IntPtr hWnd, ref COMBOBOXINFO pcbi);

[StructLayout(LayoutKind.Sequential)]
public struct COMBOBOXINFO
{
    public int cbSize;
    public RECT rcItem;
    public RECT rcButton;
    public int stateButton;
    public IntPtr hwndCombo;
    public IntPtr hwndEdit;
    public IntPtr hwndList;
}
protected override void OnResize(EventArgs e)
{
    base.OnResize(e);
    SetupEdit();
    Invalidate();
}
private int buttonWidth = SystemInformation.HorizontalScrollBarArrowWidth;
protected override void WndProc(ref Message m)
{
    if (m.Msg == 0xF)
    {
        using (var g = this.CreateGraphics())
        {
            var r = new Rectangle(2, 2,
                ClientRectangle.Width - buttonWidth - 2,
                ClientRectangle.Height - 4);
            g.FillRectangle(Brushes.White, r);
        }
    }
    base.WndProc(ref m);
}
protected override void OnVisibleChanged(EventArgs e)
{
    base.OnVisibleChanged(e);
    SetupEdit();
}
private void SetupEdit()
{
    var info = new COMBOBOXINFO();
    info.cbSize = Marshal.SizeOf(info);
    GetComboBoxInfo(this.Handle, ref info);
    SetWindowPos(info.hwndEdit, IntPtr.Zero, 3,
        (this.Height - Font.Height) / 2,
        ClientRectangle.Width - buttonWidth - 3,
        ClientRectangle.Height - Font.Height - 4,
        SWP_NOZORDER);
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
    base.OnDrawItem(e);
    e.DrawBackground();
    var txt = "";
    if (e.Index >= 0)
        txt = GetItemText(Items[e.Index]);
    TextRenderer.DrawText(e.Graphics, txt, Font, e.Bounds, 
        ForeColor, TextFormatFlags.Left | TextFormatFlags.VerticalCenter);
}

}

M.J
  • 143
  • 9
  • What specifically did you change from your existing code to get it to work? Is all of the above new code based on this question? – John Glenn Jan 31 '22 at 22:25