默认情况下,C# 组合框中的项目左对齐。 除了重写 DrawItem 方法和设置组合框绘制模式 --> DrawMode.OwnerDrawFixed 之外,是否有任何选项可用于更改此理由?
干杯
如果您不介意另一侧的下拉小部件,则可以将控件样式设置为
RightToLeft = RightToLeft.Yes
。
或
设置
DrawMode = OwnerDrawFixed;
并挂钩 DrawItem
事件,
然后像
private void comboBox1_DrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index == -1)
return;
ComboBox combo = ((ComboBox) sender);
using (SolidBrush brush = new SolidBrush(e.ForeColor))
{
e.DrawBackground();
e.Graphics.DrawString(combo.Items[e.Index].ToString(), e.Font, brush, e.Bounds, new StringFormat(StringFormatFlags.DirectionRightToLeft));
e.DrawFocusRectangle();
}
}
在 WPF 中,这就像指定 ItemContainerStyle 一样简单。在 Windows 窗体中,这有点棘手。如果没有自定义绘图,您可以在 ComboBox 上设置 RightToLeft 属性,但不幸的是,这也会影响下拉按钮。
由于 Windows 窗体使用本机 ComboBox,并且 Windows 没有像 ES_RIGHT 这样影响文本对齐的 ComboBox 样式,我认为您唯一的选择是诉诸所有者绘制。从 ComboBox 派生一个类并添加 TextAlignment 属性或其他内容可能是个好主意。然后,只有当 TextAlignment 居中或右对齐时,您才可以应用绘图。
您必须“DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed”并且 你自己的绘制方法就像这样。
protected virtual void OnDrawItem(object sender, DrawItemEventArgs e)
{
var comboBox = sender as ComboBox;
if (comboBox == null)
{
return;
}
e.DrawBackground();
if (e.Index >= 0)
{
StringFormat sf = new StringFormat();
sf.LineAlignment = StringAlignment.Center;
sf.Alignment = StringAlignment.Center;
Brush brush = new SolidBrush(comboBox.ForeColor);
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
{
brush = SystemBrushes.HighlightText;
}
e.Graphics.DrawString(comboBox.Items[e.Index].ToString(), comboBox.Font, brush, e.Bounds, sf);
}
}
不幸的是,如果组合框设置为 DropDownList,则 OwnDrawItem 的方法似乎不起作用。然后人们会看到白色背景而不是预期的灰色。所以我使用了 WPF 组合框,它看起来也不完全像“正常”组合框,但足够接近。
对我来说,实现两个属性、一种方法和一个通风口就足够了,如下所示:
public partial class RightAlignedComboBox : ElementHost {
public RightAlignedComboBox() {
InitializeComponent();
_comboBox = new() {
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch,
HorizontalContentAlignment = HorizontalAlignment.Right,
VerticalContentAlignment = VerticalAlignment.Center
};
_comboBox.SelectionChanged += comboBox_SelectionChanged;
_comboBox.MouseWheel += comboBox_MouseWheel;
this.Child = _comboBox;
}
#region Properties & Variables
private ComboBox _comboBox;
private IEnumerable<object> _items;
/// <summary>
/// Gets or sets the index specifying the currently selected item.
/// </summary>
public int SelectedIndex {
get {
return _comboBox.SelectedIndex;
}
set {
_comboBox.SelectedIndex = value;
}
}
/// <summary>
/// Gets or sets currently selected item in the combo box.
/// </summary>
public object SelectedItem {
get {
return _items.ElementAt(_comboBox.SelectedIndex);
}
set {
int selectedIndex = _items.IndexOfFirst(item => item.ToString() == value.ToString());
_comboBox.SelectedIndex = selectedIndex;
}
}
#endregion
#region Methods
/// <summary>
/// Sets the items selectable in the combo box.
/// </summary>
/// <param name="items">The items to be put in the combo box.</param>
public void SetItems(IEnumerable<object> items) {
_items = items;
_comboBox.Items.Clear();
for (int i = 0; i < items.Count(); i++) {
_comboBox.Items.Add(new ComboBoxItem() { Content = items.ElementAt(i).ToString() });
}
}
#endregion
#region Own events
/// <summary>
/// Event that is raised when the <see cref="SelectedIndex"/> changed either by clicking or by mouse wheel.
/// </summary>
public event EventHandler SelectionChangeCommitted = null;
/// <summary>
/// Raises the <see cref="SelectionChangeCommitted"/> event.
/// </summary>
private void onSelectionChangeCommitted() {
SelectionChangeCommitted?.Invoke(this, EventArgs.Empty);
}
#endregion
#region Events
private void comboBox_MouseWheel(object sender, MouseWheelEventArgs e) {
if (e.Delta < 0) {
if (_comboBox.SelectedIndex != _comboBox.Items.Count - 1) {
_comboBox.SelectedIndex++;
onSelectionChangeCommitted();
}
}
else {
if (_comboBox.SelectedIndex != 0) {
_comboBox.SelectedIndex--;
onSelectionChangeCommitted();
}
}
}
private void comboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) {
if (_comboBox.IsFocused) {
onSelectionChangeCommitted();
}
}
#endregion
}