绘制一个ListView控件比ListBox控件更加复杂:需要处理更多的细节。本例考虑了ListView的四个视图设置:View.Details
、View.List
、View.Tile
和View.SmallIcon
。
这里只绘制文本(这就是为什么没有包括View.LargeIcon
),以限制代码长度。有关绘制与ListView链接的ImageList中包含的位图的示例,请参见此处。
设置 ListView:
启用ListView的OwnerDraw
模式,然后订阅其DrawItem、DrawSubItem和DrawColumnHeader事件,如示例代码所示(如果要ListView显示任何内容,则必须这样做)。
标题使用默认渲染方式绘制(设置e.DrawDefault = true
)。
常规操作描述:
使用TextRenderer.DrawText绘制项目文本:这是ListView用于绘制项的原始方法。它允许精确匹配默认渲染效果,因此我们不会注意到文本的某些对齐问题。
DrawItem
事件用于在所有View
模式下绘制自定义背景,并在除View.Details之外的所有模式下绘制项目文本;而在View.Details
中,DrawSubItems
事件则起到作用:如果DrawItem
事件执行相同任务,则会将第一个项目的文本绘制两次。
当View
设置为Tile
或List
时,DrawSubItems
事件不会被调用。
代码说明:
一个辅助方法GetTextAlignment
负责设置项目的对齐方式,因为每个列可以具有特定的文本对齐方式。
一个名为Color listViewSelectionColor
的属性,用于设置/更改所选项目的颜色。要修改选择颜色,请将此字段设置为任何值并使用Invalidate()
方法使ListView失效:新颜色将立即应用。
结果示例:
bool lvEditMode = false;
Color listViewSelectionColor = Color.Orange;
protected void listView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
var lView = sender as ListView;
if (lvEditMode || lView.View == View.Details) return;
TextFormatFlags flags = GetTextAlignment(lView, 0);
Color itemColor = e.Item.ForeColor;
if (e.Item.Selected) {
using (var bkBrush = new SolidBrush(listViewSelectionColor)) {
e.Graphics.FillRectangle(bkBrush, e.Bounds);
}
itemColor = e.Item.BackColor;
}
else {
e.DrawBackground();
}
TextRenderer.DrawText(e.Graphics, e.Item.Text, e.Item.Font, e.Bounds, itemColor, flags);
if (lView.View == View.Tile && e.Item.SubItems.Count > 1) {
var subItem = e.Item.SubItems[1];
flags = GetTextAlignment(lView, 1);
TextRenderer.DrawText(e.Graphics, subItem.Text, subItem.Font, e.Bounds, SystemColors.GrayText, flags);
}
}
private void listView1_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
{
var lView = sender as ListView;
TextFormatFlags flags = GetTextAlignment(lView, e.ColumnIndex);
Color itemColor = e.Item.ForeColor;
if (e.Item.Selected && !lvEditMode) {
if (e.ColumnIndex == 0 || lView.FullRowSelect) {
using (var bkgrBrush = new SolidBrush(listViewSelectionColor)) {
e.Graphics.FillRectangle(bkgrBrush, e.Bounds);
}
itemColor = e.Item.BackColor;
}
}
else {
e.DrawBackground();
}
TextRenderer.DrawText(e.Graphics, e.SubItem.Text, e.SubItem.Font, e.Bounds, itemColor, flags);
}
protected void listView1_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
=> e.DrawDefault = true;
private TextFormatFlags GetTextAlignment(ListView lstView, int colIndex)
{
TextFormatFlags flags = (lstView.View == View.Tile)
? (colIndex == 0) ? TextFormatFlags.Default : TextFormatFlags.Bottom
: TextFormatFlags.VerticalCenter;
if (lstView.View == View.Details) flags |= TextFormatFlags.LeftAndRightPadding;
if (lstView.Columns[colIndex].TextAlign != HorizontalAlignment.Left) {
flags |= (TextFormatFlags)((int)lstView.Columns[colIndex].TextAlign ^ 3);
}
return flags;
}
private void listView1_BeforeLabelEdit(object sender, LabelEditEventArgs e) => lvEditMode = true;
private void listView1_AfterLabelEdit(object sender, LabelEditEventArgs e) => lvEditMode = false;
if (e.Item.Selected) =>
绘制背景(e.Graphics.FillRectangle()
)和文本。如果未被选中,则e.DrawDefault = true;
。你可以使用e.Bounds
测量来填充矩形,使用任何你想要的颜色。如果 ListView 包含任何位图,你还需要绘制它们。 - Jimi