跟随前文http://blog.csdn.net/luols/article/details/7184155的脚步继续探索,我们对重写的ListBox项背景色加以控制,让其交替变化显示,并对选中项背景色用渐变刷子,当项被选中时,背景色有一个渐变过程,我们先看下最终的效果:
关键代码在前文已有详尽描述,这里只补充三个属性,以及OnDrawItem方法的重写
三个属性(已设置默认值):
private Color _rowBackColor1 = Color.White;
private Color _rowBackColor2 = Color.FromArgb(254, 216, 249);
private Color _selectedColor = Color.FromArgb(102, 206, 255);
/// <summary>
/// 选中项背景色
/// </summary>
[Description("选中项背景色")]
public Color SelectedColor
{
get { return _selectedColor; }
set { _selectedColor = value; }
}
/// <summary>
/// 奇数项背景色
/// </summary>
[Description("奇数项背景色")]
public Color RowBackColor1
{
get { return _rowBackColor1; }
set { _rowBackColor1 = value; }
}
/// <summary>
/// 偶数项背景色
/// </summary>
[Description("偶数项背景色")]
public Color RowBackColor2
{
get { return _rowBackColor2; }
set { _rowBackColor2 = value; }
}
OnDrawItem方法(主要增加了对项背景色的控制)
protected override void OnDrawItem(DrawItemEventArgs e)
{
e.DrawBackground();
e.DrawFocusRectangle();
if (e.Index != MyListBox.NoMatches && base.Items.Count > 0)
{
Graphics g = e.Graphics;
StringFormat sf = new StringFormat();
sf.Trimming = StringTrimming.EllipsisCharacter; //超出指定矩形区域部分用"..."替代
sf.LineAlignment = StringAlignment.Center;//垂直居中
MyListBoxItem item = (MyListBoxItem)Items[e.Index];
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
{ //选中项背景色设置
RenderHelper.RenderBackgroundInternal(
g, e.Bounds, _selectedColor, _selectedColor,
Color.FromArgb(200, 255, 255, 255),
0.45f, true, LinearGradientMode.Vertical);
}
else
{
Color backColor;
if (e.Index % 2 == 0) //偶数项
{
backColor = _rowBackColor2;
}
else //奇数项
{
backColor = _rowBackColor1;
}
using (SolidBrush brush = new SolidBrush(backColor))
{
g.FillRectangle(brush, e.Bounds);
}
}
SizeF size = g.MeasureString(item.Text, e.Font); //获取项文本尺寸
if (HasIcon) //带图标时
{
if (size.Width > e.Bounds.Width - this.IconWidth) //项文本宽度超过 项宽-图标宽度
{
item.ShowTip = true; //显示tooltip
}
/* 获取指定矩形区域,注意不能直接用项所在矩形,否则DrawString时会出现自动换行
* 的情况。前面说超出指定矩形区域用“...”替代 指的是DrawString方法会先塞满整个
* 矩形区域,如果区域高度够时,就会出现自动换行的情况 ******/
RectangleF rectF = new RectangleF(e.Bounds.Left,
e.Index * this.ItemHeight + (this.ItemHeight - size.Height) / 2.0f,
e.Bounds.Width - this.IconWidth, size.Height);
//写 项文本
g.DrawString(item.Text, e.Font, new SolidBrush(e.ForeColor), rectF, sf);
if (item.ItemImage != null) //在项右侧 画图标
{
g.InterpolationMode = InterpolationMode.HighQualityBilinear;
/* 注意不能用DrawImage(img, x, y)方法,务必指定图标的大小,
* 否则会导致图标被放大,读者不妨一试 :) *****/
g.DrawImage(item.ItemImage, e.Bounds.Right - this.IconWidth, e.Bounds.Top, this.IconWidth, this.IconHeight);
}
}
else //不带图标
{
if (size.Width > e.Bounds.Width) //项文本宽度超过 项宽
{
item.ShowTip = true; //显示tooltip
}
//获取指定矩形区域
RectangleF rectF = new RectangleF(e.Bounds.Left,
e.Index * this.ItemHeight + (this.ItemHeight - size.Height) / 2.0f,
e.Bounds.Width, size.Height);
//写 项文本
g.DrawString(item.Text, e.Font, new SolidBrush(e.ForeColor), rectF, sf);
}
}
base.OnDrawItem(e);
}
这里面有一个RenderHelper类
class RenderHelper
{
public static void RenderBackgroundInternal(Graphics g, Rectangle rect,
Color baseColor, Color borderColor, Color innerBorderColor,
float basePosition, bool drawBorder, LinearGradientMode mode)
{
if (drawBorder)
{
rect.Width--;
rect.Height--;
}
using (LinearGradientBrush brush = new LinearGradientBrush(
rect, Color.Transparent, Color.Transparent, mode))
{
Color[] colors = new Color[4];
colors[0] = GetColor(baseColor, 0, 35, 24, 9);
colors[1] = GetColor(baseColor, 0, 13, 8, 3);
colors[2] = baseColor;
colors[3] = GetColor(baseColor, 0, 68, 69, 54);
ColorBlend blend = new ColorBlend();
blend.Positions = new float[] { 0.0f, basePosition, basePosition + 0.05f, 1.0f };
blend.Colors = colors;
brush.InterpolationColors = blend;
g.FillRectangle(brush, rect);
}
if (baseColor.A > 80)
{
Rectangle rectTop = rect;
if (mode == LinearGradientMode.Vertical)
{
rectTop.Height = (int)(rectTop.Height * basePosition);
}
else
{
rectTop.Width = (int)(rect.Width * basePosition);
}
using (SolidBrush brushAlpha =
new SolidBrush(Color.FromArgb(80, 255, 255, 255)))
{
g.FillRectangle(brushAlpha, rectTop);
}
}
if (drawBorder)
{
using (Pen pen = new Pen(borderColor))
{
g.DrawRectangle(pen, rect);
}
rect.Inflate(-1, -1);
using (Pen pen = new Pen(innerBorderColor))
{
g.DrawRectangle(pen, rect);
}
}
}
private static Color GetColor(Color colorBase, int a, int r, int g, int b)
{
int a0 = colorBase.A;
int r0 = colorBase.R;
int g0 = colorBase.G;
int b0 = colorBase.B;
if (a + a0 > 255) { a = 255; } else { a = Math.Max(a + a0, 0); }
if (r + r0 > 255) { r = 255; } else { r = Math.Max(r + r0, 0); }
if (g + g0 > 255) { g = 255; } else { g = Math.Max(g + g0, 0); }
if (b + b0 > 255) { b = 255; } else { b = Math.Max(b + b0, 0); }
return Color.FromArgb(a, r, g, b);
}
}