C# WinForm控件美化扩展系列之ListView(4)-实现所有样式的美化
- 摘要:完成对ListView各种显示样式(LargeIcon、SmallIcon、List、Tile、Details)和边框、列表头的美化,修正FullRowSelect为Flase的绘制方法。
先看效果:
![]()
![]()



.NET自带的ListView控件本身就有部分BUG,例如当设置显示模式设为Tile(平铺)样式的时候,选择不同的项,就会有些选择后的背景没有完全刷新,会留下部分聚焦框。在美化的过程中,我尽量注意了这些问题,但是也没有做过多的测试,也有可能存在一些问题,首先说一下到目前已经实现了的和没有实现的功能。
实现的功能:
1、 换边框颜色。
2、 当显示模式为Details 和 List时,间隔的项显示不同的背景色。
3、 当显示模式为Details时,对列表头的美化。
4、 各种显示样式(LargeIcon、SmallIcon、List、Tile、Details)的项选择后的背景美化。
没有实现的功能:
1、 不支持显示CheckBox。这个不是不能画出来,问题是获取不到CheckBox显示的位置,因为只有点击的是系统默认的CheckBox的位置,那个项才会被选中,自己绘制的CheckBox跟默认的的位置不对的话,点击了是没用的。所以就没有支持CheckBox。
对各个项的绘制,可以通过GetBounds方法得到图标和文本的所在位置和大小,就是没有获取CheckBox的。LargeIcon、SmallIcon、List显示样式的绘制比较容易,Details样式的绘制需要注意的FullRowSelect不同设置时背景的绘制,Tile样式的文本绘制麻烦些,需要分别计算每个SubItem的文本的位置和大小。图标的绘制在项不选中的情况下很简单,选中后要实现想系统自带的那种效果需要要到API函数:ImageList_GetIcon,具体的方法,来看看全部的绘制代码吧:
#region Draw Methods
internal void DrawItemInternal(DrawListViewItemEventArgs e)
{
if (base.View == View.Details)
{
return;
}
Graphics g = e.Graphics;
ListViewItem item = e.Item;
ListViewItemStates itemState = e.State;
ImageList imageList = item.ImageList;
e.DrawBackground();
bool bDrawImage =
(imageList != null) &&
(item.ImageIndex != -1 ||
!string.IsNullOrEmpty(item.ImageKey));
bool bSelected =
(itemState & ListViewItemStates.Selected) != 0;
if (bDrawImage)
{
DrawImage(g, item, bSelected);
}
if (!string.IsNullOrEmpty(item.Text))
{
Rectangle textRect =
item.GetBounds(ItemBoundsPortion.Label);
DrawBackground(g, e.ItemIndex, textRect, bSelected);
DrawText(g, item, textRect, bSelected);
}
}
private void DrawImage(
Graphics g,
ListViewItem item,
bool selected)
{
ImageList imageList = item.ImageList;
Size imageSize = imageList.ImageSize;
Rectangle imageRect = item.GetBounds(ItemBoundsPortion.Icon);
if (imageRect.Width > imageSize.Width)
{
imageRect.X += (imageRect.Width - imageSize.Width) / 2;
imageRect.Width = imageSize.Width;
}
if (imageRect.Height > imageSize.Height)
{
imageRect.Y += (imageRect.Height - imageSize.Height) / 2;
imageRect.Height = imageSize.Height;
}
int imageIndex =
item.ImageIndex != -1 ?
item.ImageIndex :
imageList.Images.IndexOfKey(item.ImageKey);
if (selected)
{
IntPtr hIcon = NativeMethods.ImageList_GetIcon(
imageList.Handle,
imageIndex,
(int)NativeMethods.ImageListDrawFlags.ILD_SELECTED);
g.DrawIcon(Icon.FromHandle(hIcon), imageRect);
NativeMethods.DestroyIcon(hIcon);
}
else
{
Image image = imageList.Images[imageIndex];
g.DrawImage(
image,
imageRect,
0,
0,
image.Width,
image.Height,
GraphicsUnit.Pixel);
}
}
private void DrawBackground(
Graphics g,
int itemIndex,
Rectangle rect,
bool selected)
{
switch (base.View)
{
case View.SmallIcon:
case View.List:
rect.Inflate(-1, 0);
break;
}
if (selected)
{
Color baseColor = _selectedColor;
Color borderColor = _selectedColor;
Color innerBorderColor =
Color.FromArgb(150, 255, 255, 255);
RenderBackgroundInternal(
g,
rect,
baseColor,
borderColor,
innerBorderColor,
0.45f,
true,
LinearGradientMode.Vertical);
}
else
{
if (base.View == View.List)
{
Color backColor = itemIndex % 2 == 0 ?
_rowBackColor1 : _rowBackColor2;
using (SolidBrush brush = new SolidBrush(backColor))
{
g.FillRectangle(brush, rect);
}
}
}
}
private void DrawText(
Graphics g,
ListViewItem item,
Rectangle textRect,
bool selected)
{
StringFormat sf = StringFormat.GenericTypographic;
switch (base.View)
{
case View.LargeIcon:
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Near;
sf.Trimming = StringTrimming.EllipsisCharacter;
sf.FormatFlags &= ~(StringFormatFlags.LineLimit);
if (selected)
{
sf.FormatFlags &= ~StringFormatFlags.NoWrap;
}
break;
case View.List:
case View.SmallIcon:
textRect.Inflate(-1, 0);
sf.Alignment = StringAlignment.Near;
sf.LineAlignment = StringAlignment.Center;
sf.Trimming = StringTrimming.EllipsisCharacter;
sf.FormatFlags &= ~(StringFormatFlags.LineLimit);
break;
case View.Tile:
textRect.Inflate(-2, 0);
sf.Alignment = StringAlignment.Near;
sf.LineAlignment = StringAlignment.Center;
sf.Trimming = StringTrimming.EllipsisCharacter;
sf.FormatFlags |= StringFormatFlags.NoWrap;
break;
}
if (base.View != View.Tile ||
item.SubItems.Count == 1)
{
using (Brush brush = new SolidBrush(item.ForeColor))
{
g.DrawString(
item.Text,
item.Font,
brush,
textRect,
sf);
}
}
else
{
string subItemText = "A";
int height;
bool bBreak = false;
Rectangle sunItemTextRect = textRect;
foreach (ListViewItem.ListViewSubItem subItem in item.SubItems)
{
if (!string.IsNullOrEmpty(subItem.Text))
{
subItemText = subItem.Text;
}
height = TextRenderer.MeasureText(
g, subItem.Text, subItem.Font).Height;
sunItemTextRect.Height = height;
if (sunItemTextRect.Bottom > textRect.Bottom)
{
sunItemTextRect.Height =
textRect.Bottom - sunItemTextRect.Y;
bBreak = true;
}
using (Brush brush = new SolidBrush(subItem.ForeColor))
{
g.DrawString(
subItemText,
subItem.Font,
brush,
sunItemTextRect,
sf);
}
sunItemTextRect.Y += height;
if (bBreak)
{
break;
}
}
}
}
private void DrawSubItemDetails(
DrawListViewSubItemEventArgs e)
{
Rectangle bounds = e.Bounds;
ListViewItemStates itemState = e.ItemState;
Graphics g = e.Graphics;
ListViewItem item = e.Item;
bool bSelected =
(itemState & ListViewItemStates.Selected) != 0;
bool bDrawImage = false;
bool bFistItem = false;
int imageIndex = -1;
if (e.ColumnIndex == 0)
{
bFistItem = true;
if (item.ImageList != null)
{
if(item.ImageIndex != -1)
{
imageIndex = item.ImageIndex;
}
else if (!string.IsNullOrEmpty(item.ImageKey))
{
imageIndex =
item.ImageList.Images.IndexOfKey(item.ImageKey);
}
if(imageIndex != -1)
{
bDrawImage = true;
}
}
}
Rectangle backRect = bounds;
Rectangle imageRect = Rectangle.Empty;
if (bDrawImage)
{
imageRect = item.GetBounds(ItemBoundsPortion.Icon);
backRect = item.GetBounds(ItemBoundsPortion.Label);
backRect.X += 2;
backRect.Width -= 2;
}
if (bSelected &&
(base.FullRowSelect ||
(!base.FullRowSelect && bFistItem)))
{
backRect.Height--;
Color baseColor = _selectedColor;
Color borderColor = _selectedColor;
Color innerBorderColor = Color.FromArgb(150, 255, 255, 255);
RenderBackgroundInternal(
g,
backRect,
baseColor,
borderColor,
innerBorderColor,
0.45f,
false,
LinearGradientMode.Vertical);
if (!base.FullRowSelect && bFistItem)
{
backRect.Width--;
using (Pen pen = new Pen(borderColor))
{
g.DrawRectangle(pen, backRect);
}
backRect.Width++;
}
else
{
Point[] points = new Point[4];
points[0] = new Point(backRect.X, backRect.Y);
points[1] = new Point(backRect.Right, backRect.Y);
points[2] = new Point(backRect.Right, backRect.Bottom);
points[3] = new Point(backRect.X, backRect.Bottom);
using (Pen pen = new Pen(borderColor))
{
if (bFistItem)
{
g.DrawLine(pen, points[0], points[1]);
g.DrawLine(pen, points[0], points[3]);
g.DrawLine(pen, points[2], points[3]);
}
if (e.ColumnIndex == ColumnCount - 1)
{
points[1].X--;
points[2].X--;
g.DrawLine(pen, points[0], points[1]);
g.DrawLine(pen, points[1], points[2]);
g.DrawLine(pen, points[2], points[3]);
}
else
{
g.DrawLine(pen, points[0], points[1]);
g.DrawLine(pen, points[2], points[3]);
}
}
}
}
else
{
Color backColor = e.ItemIndex % 2 == 0 ?
_rowBackColor1 : _rowBackColor2;
using (SolidBrush brush = new SolidBrush(backColor))
{
g.FillRectangle(brush, backRect);
}
}
TextFormatFlags flags = GetFormatFlags(e.Header.TextAlign);
if (bDrawImage)
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
if (bSelected)
{
IntPtr hIcon = NativeMethods.ImageList_GetIcon(
item.ImageList.Handle,
imageIndex,
(int)NativeMethods.ImageListDrawFlags.ILD_SELECTED);
g.DrawIcon(Icon.FromHandle(hIcon), imageRect);
NativeMethods.DestroyIcon(hIcon);
}
else
{
Image image = item.ImageList.Images[imageIndex];
g.DrawImage(
image,
imageRect,
0,
0,
image.Width,
image.Height,
GraphicsUnit.Pixel);
}
Rectangle textRect = new Rectangle(
imageRect.Right + 3,
bounds.Y,
bounds.Width - imageRect.Right - 3,
bounds.Height);
TextRenderer.DrawText(
g,
item.Text,
item.Font,
textRect,
item.ForeColor,
flags);
}
else
{
bounds.X += 3;
TextRenderer.DrawText(
g,
e.SubItem.Text,
e.SubItem.Font,
bounds,
e.SubItem.ForeColor,
flags);
}
}
#endregion
声明:
本文版权归作者和CS 程序员之窗所有,欢迎转载,转载必须保留以下版权信息,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
作者:Starts_2000
出处:CS 程序员之窗 http://www.csharpwin.com。
你可以免费使用或修改提供的源代码,但请保留源代码中的版权信息,详情请查看:
CS程序员之窗开源协议 http://www.csharpwin.com/csol.html。