要实现ListView的各行各列重绘是一件很麻烦的事情,最近就确定要实现一个功能需求,在一个ListView各行的第二列(Details模式)加入一个小图标。之前已经领教过ListView的设置,要开启重绘ListView各行,就必须重载它的OnDrawSubItem,但是ListView默认是不会执行你重载的OnDrawSubItem事件的,除非你把它OwnerDraw设置为true,即打开由用户控制绘图模式。然而让人抓狂的是,OwnerDraw=true后,整个ListView的Item/SubItem/Column全部都会空掉,即使你同时重载OnDrawSubItem/OnDrawItem/OnDrawColumnHeader并执行里面的base.OnDrawXXXXX(e),也不给你画出来。
网站上寻找了若干资料,还请教了猫猫,基本拿到的案例都是老老实实完整重绘各行;还有一个比较特别的案例,是使用发送消息方式给ListView发送LVM_SETITEM消息,让SubItem显示图标和文字,然而奇怪的是,案例提供的编译好的EXE可以实现这个功能,但通过源代码编译后却图标出不来,又经过一番资料搜索后,才知道.Net 1.x下可以实现,反而.Net 2.x下无法实现该效果(....M$是白痴么?)最终不得不放弃这个方案。
其实我只需要在ListView各行原内容的基础上添加东西而已,用不着正行重绘那么劳师动众啊,于是还是硬着头皮回去看重载事件,忽然发现了重载的事件OnDrawSubItem/OnDrawItem/OnDrawColumnHeader的参数中,都有e.DrawDefault这个东东,而且默认是e.DrawDefault == false,尝试把e.DrawDefault = true,然后再执行base.OnDrawXXXXX(e),发现ListView的内容出来了!狂喜!
原来e.DrawDefault提供的功能就是允许用户在开启用户绘画模式下依然画出原来的内容。道理弄清后,接下来就好办了。重载OnDrawColumnHeader:
引用内容
protected override void OnDrawColumnHeader (DrawListViewColumnHeaderEventArgs e
)
{
e .DrawDefault
= true
;
base .OnDrawColumnHeader
(e
)
;
}
重载OnDrawSubItem,并且在合适的SubItem上重绘你要的内容:
引用内容
protected override void OnDrawSubItem (DrawListViewSubItemEventArgs e )
{
if (e .Header
.Index
!
= theSubItemIndex
)
//theSubItemIndex是你指定要重绘的列
{
e .DrawDefault = true
;
base .OnDrawSubItem (e
)
;
}
else
{
//e.DrawBackground(), e.DrawText() , 画上你要画的东西~
}
}
OnDrawItem就不需要重载了,因为OnDrawSubItem的重绘工作已经包含了Item,而且千万别在OnDrawItem使用e.DrawDefault = true,不然OnDrawSubItem就不工作了。
效果图: