281 lines
9.4 KiB
C#
281 lines
9.4 KiB
C#
using AntdUI;
|
|
using System;
|
|
using System.ComponentModel;
|
|
using System.Drawing;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Windows.Forms;
|
|
|
|
namespace JinYuan.ControlLib
|
|
{
|
|
public partial class CustomComboBox : ComboBox
|
|
{
|
|
private Color darkBackColor = Color.FromArgb(30, 30, 30);
|
|
private Color lightBackColor = Color.White;
|
|
private Color darkForeColor = Color.White;
|
|
private Color lightForeColor = Color.Black;
|
|
private Color darkBorderColor = Color.FromArgb(64, 64, 64);
|
|
private Color lightBorderColor = Color.FromArgb(217, 217, 217);
|
|
private Color darkArrowColor = Color.White;
|
|
private Color lightArrowColor = Color.Black;
|
|
private Color darkWatermarkColor = Color.Gray;
|
|
private Color lightWatermarkColor = Color.LightGray;
|
|
|
|
private string watermarkText = string.Empty;
|
|
[Category("行为")]
|
|
public string WatermarkText
|
|
{
|
|
get { return watermarkText; }
|
|
set
|
|
{
|
|
watermarkText = value;
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
private int cornerRadius = 5; // 新增:控制圆角半径的字段
|
|
|
|
[Category("外观")]
|
|
[DefaultValue(5)]
|
|
public int CornerRadius
|
|
{
|
|
get { return cornerRadius; }
|
|
set
|
|
{
|
|
if (cornerRadius != value)
|
|
{
|
|
cornerRadius = value;
|
|
Invalidate();
|
|
}
|
|
}
|
|
}
|
|
|
|
public CustomComboBox()
|
|
{
|
|
SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);
|
|
DrawMode = DrawMode.OwnerDrawFixed;
|
|
DropDownStyle = ComboBoxStyle.DropDownList;
|
|
UpdateTheme(Config.IsDark);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void UpdateTheme(bool isDark)
|
|
{
|
|
BackColor = isDark ? darkBackColor : lightBackColor;
|
|
ForeColor = isDark ? darkForeColor : lightForeColor;
|
|
Invalidate();
|
|
}
|
|
|
|
protected override void OnPaint(PaintEventArgs e)
|
|
{
|
|
using (var path = CreateRoundedRectangle(new Rectangle(0, 0, Width - 1, Height - 1), cornerRadius))
|
|
{
|
|
var g = e.Graphics;
|
|
g.SmoothingMode = SmoothingMode.AntiAlias;
|
|
|
|
var rect = new Rectangle(0, 0, Width - 1, Height - 1);
|
|
var borderColor = Config.IsDark ? darkBorderColor : lightBorderColor;
|
|
var arrowColor = Config.IsDark ? darkArrowColor : lightArrowColor;
|
|
|
|
// Draw background
|
|
using (var brush = new SolidBrush(BackColor))
|
|
{
|
|
g.FillPath(brush, path);
|
|
}
|
|
|
|
// Draw border
|
|
using (var pen = new Pen(borderColor))
|
|
{
|
|
g.DrawPath(pen, path);
|
|
}
|
|
|
|
// Draw text or watermark
|
|
var textRect = new Rectangle(cornerRadius, 2, Width - 20 - cornerRadius, Height - 4);
|
|
var flags = TextFormatFlags.VerticalCenter | TextFormatFlags.Left;
|
|
if (SelectedItem != null)
|
|
{
|
|
string displayText = GetCustomItemText(SelectedItem);
|
|
using (var brush = new SolidBrush(ForeColor))
|
|
{
|
|
TextRenderer.DrawText(g, displayText, Font, textRect, ForeColor, flags);
|
|
}
|
|
}
|
|
else if (!string.IsNullOrEmpty(watermarkText))
|
|
{
|
|
var watermarkColor = Config.IsDark ? darkWatermarkColor : lightWatermarkColor;
|
|
TextRenderer.DrawText(g, watermarkText, Font, textRect, watermarkColor, flags);
|
|
}
|
|
|
|
// Draw arrow
|
|
var arrowSize = 8;
|
|
var arrowRect = new Rectangle(Width - arrowSize - 8 - cornerRadius, (Height - arrowSize) / 2, arrowSize, arrowSize);
|
|
using (var brush = new SolidBrush(arrowColor))
|
|
{
|
|
Point[] arrow = {
|
|
new Point(arrowRect.Left, arrowRect.Top),
|
|
new Point(arrowRect.Right, arrowRect.Top),
|
|
new Point(arrowRect.Left + arrowRect.Width / 2, arrowRect.Bottom)
|
|
};
|
|
g.FillPolygon(brush, arrow);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override void OnDrawItem(DrawItemEventArgs e)
|
|
{
|
|
if (e.Index < 0) return;
|
|
|
|
// 设置下拉项的背景色
|
|
Color backColor;
|
|
Color textColor;
|
|
|
|
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
|
|
{
|
|
// 选中项的颜色
|
|
backColor = Config.IsDark ? Color.FromArgb(45, 45, 45) : Color.FromArgb(230, 230, 230);
|
|
textColor = Config.IsDark ? darkForeColor : lightForeColor;
|
|
}
|
|
else
|
|
{
|
|
// 未选中项的颜色
|
|
backColor = Config.IsDark ? darkBackColor : lightBackColor;
|
|
textColor = Config.IsDark ? darkForeColor : lightForeColor;
|
|
}
|
|
|
|
// 使用新的背景色绘制背景
|
|
using (var backBrush = new SolidBrush(backColor))
|
|
{
|
|
e.Graphics.FillRectangle(backBrush, e.Bounds);
|
|
}
|
|
|
|
// 绘制文本
|
|
if (e.Index >= 0)
|
|
{
|
|
string itemText = GetCustomItemText(Items[e.Index]);
|
|
|
|
// 设置文本边距
|
|
Rectangle textBounds = new Rectangle(
|
|
e.Bounds.X + 5, // 左边距
|
|
e.Bounds.Y,
|
|
e.Bounds.Width - 10, // 右边距
|
|
e.Bounds.Height
|
|
);
|
|
|
|
// 使用TextRenderer绘制文本以获得更好的文本渲染效果
|
|
TextRenderer.DrawText(
|
|
e.Graphics,
|
|
itemText,
|
|
Font,
|
|
textBounds,
|
|
textColor,
|
|
TextFormatFlags.VerticalCenter | TextFormatFlags.Left
|
|
);
|
|
}
|
|
|
|
// 如果有焦点,绘制焦点矩形
|
|
if ((e.State & DrawItemState.Focus) == DrawItemState.Focus)
|
|
{
|
|
using (Pen focusPen = new Pen(Config.IsDark ? Color.FromArgb(70, 70, 70) : Color.FromArgb(180, 180, 180)))
|
|
{
|
|
e.Graphics.DrawRectangle(focusPen, new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width - 1, e.Bounds.Height - 1));
|
|
}
|
|
}
|
|
}
|
|
|
|
// 添加这个方法来处理下拉列表的外观
|
|
protected override void WndProc(ref System.Windows.Forms.Message m)
|
|
{
|
|
if (m.Msg == 0x204E) // WM_CTLCOLORLISTBOX
|
|
{
|
|
// 获取下拉列表的句柄
|
|
var hDC = m.WParam;
|
|
var hListBox = m.LParam;
|
|
|
|
using (Graphics g = Graphics.FromHdc(hDC))
|
|
{
|
|
// 设置下拉列表的背景色
|
|
using (SolidBrush backBrush = new SolidBrush(Config.IsDark ? darkBackColor : lightBackColor))
|
|
{
|
|
g.FillRectangle(backBrush, this.DropDownRectangle);
|
|
}
|
|
}
|
|
}
|
|
base.WndProc(ref m);
|
|
}
|
|
|
|
// 获取下拉列表的矩形区域
|
|
private Rectangle DropDownRectangle
|
|
{
|
|
get
|
|
{
|
|
return new Rectangle(0, 0, DropDownWidth, ItemHeight * Math.Max(Items.Count, 1));
|
|
}
|
|
}
|
|
|
|
private string GetCustomItemText(object item)
|
|
{
|
|
if (item == null)
|
|
return string.Empty;
|
|
|
|
if (string.IsNullOrEmpty(DisplayMember))
|
|
return item.ToString();
|
|
|
|
PropertyDescriptor descriptor = TypeDescriptor.GetProperties(item).Find(DisplayMember, true);
|
|
if (descriptor != null)
|
|
return descriptor.GetValue(item)?.ToString() ?? string.Empty;
|
|
|
|
return item.ToString();
|
|
}
|
|
|
|
public object GetSelectedValue()
|
|
{
|
|
if (SelectedItem == null)
|
|
return null;
|
|
|
|
if (string.IsNullOrEmpty(ValueMember))
|
|
return SelectedItem;
|
|
|
|
PropertyDescriptor descriptor = TypeDescriptor.GetProperties(SelectedItem).Find(ValueMember, true);
|
|
if (descriptor != null)
|
|
return descriptor.GetValue(SelectedItem);
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
private GraphicsPath CreateRoundedRectangle(Rectangle bounds, int radius)
|
|
{
|
|
int diameter = radius * 2;
|
|
Size size = new Size(diameter, diameter);
|
|
Rectangle arc = new Rectangle(bounds.Location, size);
|
|
GraphicsPath path = new GraphicsPath();
|
|
|
|
if (radius == 0)
|
|
{
|
|
path.AddRectangle(bounds);
|
|
return path;
|
|
}
|
|
|
|
// 左上角
|
|
path.AddArc(arc, 180, 90);
|
|
|
|
// 右上角
|
|
arc.X = bounds.Right - diameter;
|
|
path.AddArc(arc, 270, 90);
|
|
|
|
// 右下角
|
|
arc.Y = bounds.Bottom - diameter;
|
|
path.AddArc(arc, 0, 90);
|
|
|
|
// 左下角
|
|
arc.X = bounds.Left;
|
|
path.AddArc(arc, 90, 90);
|
|
|
|
path.CloseFigure();
|
|
return path;
|
|
}
|
|
}
|
|
}
|