8
votes

I have a form with a ComboBox. I found the post: http://blog.michaelgillson.org/2010/05/18/left-right-center-where-do-you-align/ that helped me to centre-align all the items in the DropDown list. The problem is that the selected item (the item shown in the comboBox.Text property) remains left aligned.

How can I centre-align also the selected Item?
The code is:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ComboBoxTextProperty
{
    public partial class Form3 : Form
    {
        public Form3()
        {
            InitializeComponent();

            List<string> source = new List<string>() { "15", "63", "238", "1284", "13561" };
            comboBox1.DataSource = source;
            comboBox1.DrawMode = DrawMode.OwnerDrawFixed;
            comboBox1.DropDownStyle = ComboBoxStyle.DropDown;
            comboBox1.SelectedIndex = 0;
            comboBox1.DrawItem += new DrawItemEventHandler(ComboBox_DrawItem);
    }

    /// <summary>
    /// Allow the text in the ComboBox to be center aligned.
    /// Change the DrawMode Property from Normal to either OwnerDrawFixed or OwnerDrawVariable.
    /// If DrawMode is not changed, the DrawItem event will NOT fire and the DrawItem event handler will not execute.
    /// For a DropDownStyle of DropDown, the selected item remains left aligned but the expanded dropped down list is centered.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
    {
        ComboBox comboBox1 = sender as ComboBox; // By using sender, one method could handle multiple ComboBoxes.
        if (comboBox1 != null)
        {
            e.DrawBackground(); // Always draw the background.               
            if (e.Index >= 0) // If there are items to be drawn.
            {
                StringFormat format = new StringFormat(); // Set the string alignment.  Choices are Center, Near and Far.
                format.LineAlignment = StringAlignment.Center;
                format.Alignment = StringAlignment.Center;

                // Set the Brush to ComboBox ForeColor to maintain any ComboBox color settings.
                // Assumes Brush is solid.
                Brush brush = new SolidBrush(comboBox1.ForeColor);
                if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) // If drawing highlighted selection, change brush.
                {
                    brush = SystemBrushes.HighlightText;
                }
                e.Graphics.DrawString(comboBox1.Items[e.Index].ToString(), comboBox1.Font, brush, e.Bounds, format); // Draw the string.
            }
        }
    }
}
}
1
You also need to override the Paint event to do that. I suggest that you create a new derived class from the ComboBox control and override both OnPaint and OnDrawItem.user10216583
Also Center the text of a combobox should help.user10216583

1 Answers

9
votes

To make the text horizontally centered, you need to do two things:

  1. To center-align dropdown menu items, make the ComboBox owner-draw and draw the items yourself, center-aligned.
  2. To center-align the text area of the control, find the Edit control of the ComboBox and set ES_CENTER style for it to make it center-aligned as well.

enter image description here

You may also be interested to this post: ComboBox Text Align Vertically Center.

Example

To make the dropdown text align at center, you need to handle drawing of items yourself. To do so, set DrawMode property of ComboBox to OwnerDrawFixed. Then you can handle DrawItem event or override OnDrawItem.

To set the alignment of text area to center, you need to find the Edit control owned by ComboBox. To do so, you can use GetComboBoxInfo method which returns a COMBOBOXINFO. The next step is calling GetWindowLong method to get styles of the edit control and then add ES_CENTER and then call SetWindowLong to set the new style.

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class MyComboBox : ComboBox
{
    public MyComboBox()
    {
        DrawMode = DrawMode.OwnerDrawFixed;
    }

    [DllImport("user32.dll")]
    static extern int GetWindowLong(IntPtr hWnd, int nIndex);
    [DllImport("user32.dll")]
    static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
    const int GWL_STYLE = -16;
    const int ES_LEFT = 0x0000;
    const int ES_CENTER = 0x0001;
    const int ES_RIGHT = 0x0002;
    [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; } }
    }
    [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 OnHandleCreated(EventArgs e)
    {
        base.OnHandleCreated(e);
        SetupEdit();
    }
    private int buttonWidth = SystemInformation.HorizontalScrollBarArrowWidth;
    private void SetupEdit()
    {
        var info = new COMBOBOXINFO();
        info.cbSize = Marshal.SizeOf(info);
        GetComboBoxInfo(this.Handle, ref info);
        var style = GetWindowLong(info.hwndEdit, GWL_STYLE);
        style |= 1;
        SetWindowLong(info.hwndEdit, GWL_STYLE, style);
    }
    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.HorizontalCenter);
    }
}

Note: I put the whole logic inside a derived control called MyComboBox to make it more reusable and easier to apply, however, obviously you can do this without inheritance and just by relying on the events of an existing ComboBox control. You can also enhance the code a bit by adding a TextAlignment property which allows setting the text alignment.