ListBox 在C# winform编程中,使用的比较多,用途也很广,今天带大家一步步的美化ListBox控件。
本文主要实现。
1.奇数行与偶数行颜色交替。
2.选中行颜色。
3.鼠标移动停留行颜色。
4.增加序号
5.增加单选框显示。
前面的若干文章,已经讲解了重绘等一些技巧,这篇文章,理解内容相对比较多,看的小伙伴可以收藏,若碰到问题,欢迎在下方留言。
重绘第一步依然
新建一个类 ,继承ListBox
文中写的部分在之前文章提到过,本文不做详细描述,主要就是减少闪烁,双缓存等。
构造函数中内容
public class WenListBox : ListBox
{
public WenListBox()
{
base.SetStyle(
//ControlStyles.UserPaint |
ControlStyles.DoubleBuffer |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.ResizeRedraw |
ControlStyles.SupportsTransparentBackColor, true);
base.UpdateStyles();
this.DrawMode = DrawMode.OwnerDrawFixed;
this.IntegralHeight = false;
}
}
ControlStyles.UserPaint 此项是所有内容都由用户绘制,一般不用为true。若是需要全部用户自定义绘制。高级重绘,应当此项勾选,本文主要是绘制项,就不把此项设置为true。
私有属性
#region 私有属性
//选中项改变之前的选中项索引
private int selectBefore = -1;
private int MouseItemIndex;
private bool line = true;
private bool radioBox = true;
private Color oneRowColor = Color.DeepSkyBlue;
private Color towRowColor = Color.Aquamarine;
private Color selectedRowColor = Color.DarkCyan;
private Color mouseMoveRowColor = Color.Cyan;
private int itemHeight=20;
#endregion
公有属性
#region 公有属性
[Category("Wen"), Description("是否增加序号"), DefaultValue(true)]
public bool Line { get => line; set { line = value; this.Invalidate(); } }
[Category("Wen"), Description("是否增加选框"), DefaultValue(true)]
public bool RadioBox { get => radioBox; set { radioBox = value; this.Invalidate(); } }
[Category("Wen"), Description("奇数行颜色"), DefaultValue(typeof(Color), "DeepSkyBlue")]
public Color OneRowColor { get => oneRowColor; set { oneRowColor = value; this.Invalidate(); } }
[Category("Wen"), Description("偶数行颜色"), DefaultValue(typeof(Color), "Aquamarine")]
public Color TowRowColor { get => towRowColor; set { towRowColor = value; this.Invalidate(); } }
[Category("Wen"), Description("选中颜色"), DefaultValue(typeof(Color), "DarkCyan")]
public Color SelectedRowColor { get => selectedRowColor; set { selectedRowColor = value; this.Invalidate(); } }
[Category("Wen"), Description("鼠标移动行颜色"), DefaultValue(typeof(Color), "Cyan")]
public Color MouseMoveRowColor { get => mouseMoveRowColor; set { mouseMoveRowColor = value; this.Invalidate(); } }
#endregion
每一项都有详细备注描述,就不多做解释。若有不明白欢迎在文中评论留言转发。
部分属性重写,主要目的是按照自定义修改。重置属性或者重写属性
#region 重置属性或者重写属性
[Category("Wen"), Description("设置单项高度"), DefaultValue(20)]
public new int ItemHeight { get => itemHeight; set { base.ItemHeight = value; itemHeight = value; } }
#endregion
此处贴一个常用方法颜色获取Brush,当然此方法一般可以直接写在代码中没必要专门用一个方法,本文主要便于理解,一般在编程中,都会用using。本文不演示,后续文章转成解释using的使用。
#region 颜色获取Brush
private Brush GetBrush(string b)
{
return new SolidBrush(ColorTranslator.FromHtml(b));
}
private Brush GetBrush(Color c)
{
return new SolidBrush(c);
}
#endregion
执行重绘必要因素
ListBox 由于目前重绘只重绘项,不直接全部重绘,所以只需要重写OnDrawItem
贴代码块
//重绘指定项
protected override void OnDrawItem(DrawItemEventArgs e)
{
//base.OnDrawItem(e);
if (Items.Count == 0 || e.Index < 0)
return;
Graphics g = e.Graphics;
Rectangle rec = GetItemRectangle(e.Index);
if (GetSelected(e.Index))
{
rec.Inflate(0, -2);
ItemDraw(e.Index, g, rec, SelectedRowColor, e);
}
else if (e.Index == MouseItemIndex)
{
ItemDraw(e.Index, g, rec, MouseMoveRowColor, e);
}
else if (e.Index % 2 != 1)
{
ItemDraw(e.Index, g, rec, OneRowColor, e);
}
else
{
ItemDraw(e.Index, g, rec, TowRowColor, e);
}
}
ItemDraw由于重绘重绘可利用代码较多,本文主要用了一个方法来实现。
//刷新指定项目
private void ItemDraw(int index, Graphics g, Rectangle rec, Color c, DrawItemEventArgs e)
{
ControlHelper.SetGDIHigh(g);
g.FillRectangle(GetBrush(c), rec);
Brush brush = GetBrush(e.ForeColor);
int radioWidth = 0;
if (RadioBox)
{
radioWidth = 20;
Pen pen = new Pen(Color.Gray, 3);
g.DrawEllipse(new Pen(brush) { Width=2}, new Rectangle(rec.X, (ItemHeight - 15) / 2 + rec.Y, 15, 15));
if (GetSelected(index))
g.FillEllipse(brush, new Rectangle(rec.X + 5, (ItemHeight - 5) / 2 + rec.Y, 5, 5));
}
//绘制文字
if (Line)
{
Rectangle recLine = new Rectangle(rec.X + radioWidth, rec.Y, 50 - radioWidth, this.ItemHeight);
Rectangle recText = new Rectangle(rec.X + 50, rec.Y, rec.Width - 50, this.ItemHeight);
g.DrawString((index + 1).ToString(), Font, brush, recLine, ControlHelper.StringConters);
g.DrawString(Items[index]?.ToString(), Font, brush, recText, ControlHelper.StringConters);
}
else
{
Rectangle recText = new Rectangle(rec.X + radioWidth, rec.Y, rec.Width - radioWidth, this.ItemHeight);
g.DrawString(Items[index]?.ToString(), Font, brush, recText, ControlHelper.StringConters);
}
}
接下来 解决鼠标移动项目颜色改变
//鼠标移动
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
int index = IndexFromPoint(e.Location);
if (index < 0) return;
if (MouseItemIndex != index)
{
int indexBefore = MouseItemIndex;
MouseItemIndex = index;
this.RefreshItem(index);
this.RefreshItem(indexBefore);
}
}
鼠标离开指定项
//鼠标移开事件
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
int index = MouseItemIndex;
MouseItemIndex = -1;
RefreshItem(index);
}
选中索引变化
//选中索引变化
protected override void OnSelectedIndexChanged(EventArgs e)
{
base.OnSelectedIndexChanged(e);
if (selectBefore != -1)
{
RefreshItem(selectBefore);
}
selectBefore = SelectedIndex;
object item = this.SelectedItem;
ItemClick?.Invoke(this, new WenListBoxEventArgs(item));
}
刷新指定索引项
//刷新指定索引项
protected override void RefreshItem(int index)
{
if (index < 0 || Items.Count == 0)
return;
Graphics g = CreateGraphics();
Rectangle rec = GetItemRectangle(index);
g.SetClip(new Rectangle(rec.X, rec.Y+1, rec.Width, rec.Height-1));
if (SelectedIndex == index)
OnDrawItem(new DrawItemEventArgs(g, Font, rec, index, DrawItemState.Selected, Color.White, this.SelectedRowColor));
else
OnDrawItem(new DrawItemEventArgs(g, Font, rec, index, DrawItemState.None, this.ForeColor, this.SelectedRowColor));
}
到目前为止重绘已经完成,当然在常用中一般还需要增加项点击事件,可以按照需求自写一个委托事件。
写一个委托事件。 贴完整代码块
public delegate void WenListBoxEventHandler(object sender, WenListBoxEventArgs e);
public class WenListBoxEventArgs : EventArgs { public WenListBoxEventArgs(object item) { this.Item = item; } public object Item { get; set; } }
委托 项被点击事件
#region 委托事件
[Category("Wen"), Description("项被点击事件")]
public event WenListBoxEventHandler ItemClick;
#endregion
至此一个完整listbox重绘已经完成。
至此一个ListBox重绘完成。
关注文林软控。带你用C# 美化.NET控件。