Winforms ListView选择图?

是否有可能覆盖listview详细选择油漆? 看起来半透明的蓝色覆盖在项目上,就像在资源管理器窗口中一样。

我想在选择周围画一个轮廓来表示选择。

有什么办法吗? 赞赏的例子。

这是一个快速工作的例子,我正在搞乱。

第一个辅助结构和枚举。

[StructLayout(LayoutKind.Sequential)] public struct DRAWITEMSTRUCT { public int CtlType; public int CtlID; public int itemID; public int itemAction; public int itemState; public IntPtr hwndItem; public IntPtr hDC; public RECT rcItem; public IntPtr itemData; } [StructLayout(LayoutKind.Sequential)] public struct RECT { public int left; public int top; public int right; public int bottom; public int Width { get { return right - left; } } public int Height { get { return bottom - top; } } } public enum ListViewDefaults { LVS_OWNERDRAWFIXED = 0x0400 } public enum WMDefaults { WM_DRAWITEM = 0x002B, WM_REFLECT = 0x2000 } 

现在创建一个自定义ListView和覆盖CreateParamsWndProc

 public class CustomListView : ListView { protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; //add OwnerDraw style...i took this idea from Reflecting against ListView // bit OR is very important, otherwise you'll get an exception cp.Style |= (int)ListViewDefaults.LVS_OWNERDRAWFIXED; return cp; } } protected override void WndProc(ref Message m) { base.WndProc(ref m); //if we are drawing an item then call our custom Draw. if (m.Msg == (int)(WMDefaults.WM_REFLECT | WMDefaults.WM_DRAWITEM)) ProcessDrawItem(ref m); } 

现在是最重要的部分……绘图。 我在绘画时非常业余,但这应该让你知道该怎么做。

  private void ProcessDrawItem(ref Message m) { DRAWITEMSTRUCT dis = (DRAWITEMSTRUCT)Marshal.PtrToStructure(m.LParam, typeof(DRAWITEMSTRUCT)); Graphics g = Graphics.FromHdc(dis.hDC); ListViewItem i = this.Items[dis.itemID]; Rectangle rcItem = new Rectangle(dis.rcItem.left, dis.rcItem.top, this.ClientSize.Width, dis.rcItem.Height); //we have our rectangle. //draw whatever you want if (dis.itemState == 17) { //item is selected g.FillRectangle(new SolidBrush(Color.Red), rcItem); g.DrawString(i.Text, new Font("Arial", 8), new SolidBrush(Color.Black), new PointF(rcItem.X, rcItem.Y+1)); } else { //regular item g.FillRectangle(new SolidBrush(Color.White), rcItem); g.DrawString(i.Text, new Font("Arial", 8), new SolidBrush(Color.Black), new PointF(rcItem.X, rcItem.Y+1)); } //we have handled the message m.Result = (IntPtr)1; } 

结果就是这样。

替代文字http://sofzh.miximages.com/c%23/adf9dx.jpg

.NET ListView支持所有者绘图比其他答案建议更直接。 你甚至不需要子类。 将OwnerDraw设置为true,侦听DrawSubItem事件,然后在该事件中您可以绘制您喜欢的内容。

与往常一样, ObjectListView使这个过程更容易。 这个页面记录了如何执行此操作的严格要求。 如果你对用户有意义,你可以设置这样的东西: alt text http://sofzh.miximages.com/c%23/ownerdrawn-example1.png

但是,如果你想在细胞本身的范围之外绘制一些东西,这些技术都不会起作用。 因此,如果您希望在整个行周围绘制一个与前一行和后续行重叠的选择轮廓,则无法通过所有者绘制来执行此操作。 每个单元格都是单独绘制的,并“拥有”它的部分屏幕,擦除已存在的任何内容。

要做一些你要问的事情,你必须截取自定义绘图的后期绘画阶段(不是所有者绘制.Michael Dunn为CodeProject 写了一个很好的自定义绘图介绍 )。 您可以在这里阅读所需内容。

我讨厌说,但最简单的答案是使用ObjectListView,创建一个装饰并安装它:

 public void InitializeSelectionOverlay() { this.olv1.HighlightForegroundColor = Color.Black; this.olv1.HighlightBackgroundColor = Color.White; this.olv1.AddDecoration(new SelectedRowDecoration()); } public class SelectedRowDecoration : IOverlay { public void Draw(ObjectListView olv, Graphics g, Rectangle r) { if (olv.SelectedIndices.Count != 1) return; Rectangle rowBounds = olv.GetItem(olv.SelectedIndices[0]).Bounds; rowBounds.Inflate(0, 2); GraphicsPath path = this.GetRoundedRect(rowBounds, 15); g.DrawPath(new Pen(Color.Red, 2.0f), path); } private GraphicsPath GetRoundedRect(RectangleF rect, float diameter) { GraphicsPath path = new GraphicsPath(); RectangleF arc = new RectangleF(rect.X, rect.Y, diameter, diameter); path.AddArc(arc, 180, 90); arc.X = rect.Right - diameter; path.AddArc(arc, 270, 90); arc.Y = rect.Bottom - diameter; path.AddArc(arc, 0, 90); arc.X = rect.Left; path.AddArc(arc, 90, 90); path.CloseFigure(); return path; } } 

这给出了如下所示的内容: alt text http://sofzh.miximages.com/c%23/97v1id.png

我的第一个想法是inheritanceListView控件,将OwnerDraw设置为true并自己执行所有绘图,但这对于这么小的更改来说似乎有些过分。

然而,在我的网络漫游中,我发现这篇文章可能会有所帮助,因为它与你的情况非常相似,并且允许你自己避免绘制所有内容。