如何在WinForms中使ComboBox中的选定项目居中对齐?

8
我有一个带ComboBox的表单。我找到了这篇文章:http://blog.michaelgillson.org/2010/05/18/left-right-center-where-do-you-align/,它帮助我将DropDown列表中的所有项目居中对齐。问题是所选项目(显示在comboBox.Text属性中的项目)仍然左对齐。
如何使所选项目也居中对齐? 代码如下:
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.
            }
        }
    }
}
}

您还需要重写 Paint 事件才能实现。我建议您从 ComboBox 控件创建一个新的派生类,并重写 OnPaintOnDrawItem 两个方法。 - user10216583
此外,居中显示组合框的文本也应该有所帮助。 - user10216583
1个回答

9

要使文本水平居中,您需要做两件事:

  1. 为了使下拉菜单项居中对齐,需要将ComboBox设置为自定义绘制并自己绘制项目,使其居中对齐。
  2. 为了使控件的文本区域居中对齐,需要找到ComboBoxEdit控件,并为其设置ES_CENTER样式,使其也居中对齐。

enter image description here

您可能也对这篇文章感兴趣: ComboBox文本垂直居中对齐

示例

要使下拉文本垂直居中对齐,您需要自行处理项目的绘制。为此,请将ComboBoxDrawMode属性设置为OwnerDrawFixed。然后您可以处理DrawItem事件或覆盖OnDrawItem

为了将文本区域的对齐方式设置为中心,您需要找到由ComboBox拥有的Edit控件。为此,您可以使用GetComboBoxInfo方法返回COMBOBOXINFO。下一步是调用GetWindowLong方法获取编辑控件的样式,然后添加ES_CENTER,最后调用SetWindowLong以设置新样式。
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);
    }
}

注意:我将整个逻辑放在一个派生控件中,称为MyComboBox,以使其更易于重用和应用,但显然您可以不依赖继承,只需依赖现有ComboBox控件的事件来完成这个操作。您还可以通过添加TextAlignment属性来增强代码,从而允许设置文本对齐方式。

2
我将整个逻辑放在一个派生控件MyComboBox中,以使其更具可重用性和易于应用。然而,显然您可以不使用继承,仅依靠现有的ComboBox控件的事件来完成此操作。 - Reza Aghaei
支持/兼容的函数应为GetWindowLongPtrSetWindowLongPtr(我还忘了提到它,现在才想起来)。我发现这个声明在我测试过的所有情况下都有效:[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] internal static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong);。对于GetWindowLongPtr也是一样(当然不包括IntPtr dwNewLong)。在32位应用程序中,这些函数会自动回退到以前的版本。 - Jimi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接