最近在winform应用中需要用到可分组的数据列表功能,DataGridView默认没有提供分组的功能,而OutlookGrid(http://www.codeproject.com/KB/grid/OutlookGrid.aspx)用起来又是相当的麻烦,最后发现了ObjectListView(objectlistview.sourceforge.net),功能相当的强大,强大到我不需要那么多的功能,额~~所以决定参照它的实现,对ListView做一个简单的扩展(注:本文仅针对ListView的View属性为Details)。

首先为ListView添加好列:

listViewEx1.Columns.AddRange(new ColumnHeader[] { new ColumnHeader("列1"), new ColumnHeader("列2"), new ColumnHeader("列3") });

分组

这是ListView自带的功能,用起来也很简单,只需要把ShowGroups设置为true(默认为true),再为ListView添加ListViewGroup,并为ListViewItem设置Group即可,代码如下:

ListViewGroup g = new ListViewGroup("分组");
listViewEx1.Groups.Add(g);
ListViewItem item = new ListViewItem("数据项", g);
listViewEx1.Items.Add(item);

接下来的重绘方法,就需要通过继承ListView并重写OnDrawSubItem(DrawListViewSubItemEventArgs e)方法来实现,在重写此方法之前,必须设置ListView的OwnerDraw属性为true,用于启用重绘。

给ListViewSubItem设置图标

ListView默认可以设置ImageIndex来显示图标,但是只能设置在每个ListViewItem上,即每一行数据只能有一个图标,若要每个ListViewSubItem都能设置图标,则需要通过重写OnDrawSubItem(DrawListViewSubItemEventArgs e)方法来实现,关键代码为:

Graphics g = e.Graphics;
Rectangle r = e.Bounds;
Rectangle imageBounds = new Rectangle(r.Location, image.Size);//image为具体的图标文件
g.DrawImage(image, imageBounds);//通过DrawImage方法绘制图标

对这种方法简单的改造,可以为每一列设置单独的图标。

网格线

ListView在设置了分组的情况下,GridLines属性就无效了,所以如果需要显示网格线,也需要通过重写OnDrawSubItem(DrawListViewSubItemEventArgs e)方法来实现,关键代码为:

Graphics g = e.Graphics;
Rectangle r = e.Bounds;
using (Pen pen = new Pen(Color.Gray))
{
    g.DrawRectangle(pen, r.X, r.Y, r.Width, r.Height + 1);//高度加1使横向线条重叠
}

以上代码画了灰色的网格线,也可以简单改造以实现自定义的网络线颜色。

选中的背景

在重写OnDrawSubItem(DrawListViewSubItemEventArgs e)方法之后,选中ListView的行,默认的背景色不会出现,所以还得把选中状态的背景色显示出来,关键代码为:

    if ((e.ItemState & ListViewItemStates.Selected)
== ListViewItemStates.Selected)
    {
        using (SolidBrush brush = new SolidBrush(Color.Blue))
        {
            g.FillRectangle(brush, r);
        }
    }

以上代码为选中的列绘制了蓝色的背景,同样也可以扩展以上代码来实现自定义背景色。

呈现原始文本

在重写OnDrawSubItem(DrawListViewSubItemEventArgs e)之后,原来的文本内容同样也会像背景一样丢失了,所以需要把原来的文本重新绘制出来,关键代码如下:

Graphics g = e.Graphics;
Rectangle r = e.Bounds;
TextRenderer.DrawText(
    g,
    e.SubItem.Text,
    e.SubItem.Font,
    r,
    e.SubItem.ForeColor,
    TextFormatFlags.Left);

其他

1、自动调整列大小:调用AutoResizeColumns方法,listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent) 
2、隐藏列头:设置HeaderStyle属性,listView1.HeaderStyle = ColumnHeaderStyle.None 
3、选择整行:设置FullRowSelect为true 
4、行双击事件:绑定ListView的MouseDoubleClick事件,代码如下:

void listView1_MouseDoubleClick(object sender, MouseEventArgs e)
{
    ListViewHitTestInfo info = listView1.HitTest(e.Location);
    if (info != null && info.Item != null)
    {
        //...
    }
}

完整的代码

public class ListViewEx : ListView
{
    public ListViewEx() :
        base()
    {
        this.OwnerDraw = true;//用于启用重绘
    }
 
    /// <summary>
    /// 图标
    /// </summary>
    public Image Icon { get; set; }
 
    /// <summary>
    /// 重绘图标
    /// </summary>
    public bool IsDrawIcon { get; set; }
 
    /// <summary>
    /// 重绘网格线
    /// </summary>
    public bool IsDrawGridLines { get; set; }
 
    /// <summary>
    /// 重绘图标列
    /// </summary>
    /// <param name="e"></param>
    protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e)
    {
        if (View != View.Details ||
            e.ItemIndex == -1)
        {
            e.DrawDefault = true;
            return;
        }
 
        Rectangle r = e.Bounds;
        Graphics g = e.Graphics;
 
        DrawSelectedBackground(e, g, r);
 
        int paddingLeft = 0;
        if (IsDrawIcon)
        {
            paddingLeft = this.DrawIcon(g, r, this.Icon, e.Item.BackColor).Width;
        }
 
        if (IsDrawGridLines)
        {
            using (Pen pen = new Pen(Color.Gray))
            {
                g.DrawRectangle(pen, r.X, r.Y, r.Width, r.Height + 1);//高度加1使横向线条重叠
            }
        }
 
        if (!string.IsNullOrEmpty(e.SubItem.Text))
        {
            this.DrawText(e, g, r, paddingLeft);
        }
    }
 
    /// <summary>
    /// 重绘选中时背景
    /// </summary>
    private void DrawSelectedBackground(DrawListViewSubItemEventArgs e, Graphics g, Rectangle r)
    {
        if ((e.ItemState & ListViewItemStates.Selected)
== ListViewItemStates.Selected)
        {
            using (SolidBrush brush = new SolidBrush(Color.Blue))
            {
                g.FillRectangle(brush, r);
            }
        }
    }
 
    /// <summary>
    /// 重绘图标
    /// </summary>
    private Size DrawIcon(Graphics g, Rectangle r, Image image, Color backColor)
    {
        Rectangle imageBounds = new Rectangle(r.Location, image.Size);
        if (image.Height > r.Height)
        {
            float scaleRatio = (float)r.Height / (float)image.Height;
            imageBounds.Width = (int)((float)Icon.Width * scaleRatio);
            imageBounds.Height = r.Height - 1;
        }
        //使图标不会紧贴着每一列的左上角
        imageBounds.X += 1;
        imageBounds.Y += 1;
 
        g.DrawImage(image, imageBounds);
        return imageBounds.Size;
    }
 
    /// <summary>
    /// 重绘文本
    /// </summary>
    private void DrawText(DrawListViewSubItemEventArgs e, Graphics g, Rectangle r, int paddingLeft)
    {
        TextFormatFlags flags = GetFormatFlags(e.Header.TextAlign);
 
        r.X += 1 + paddingLeft;//重绘图标时,文本右移
        TextRenderer.DrawText(
            g,
            e.SubItem.Text,
            e.SubItem.Font,
            r,
            e.SubItem.ForeColor,
            flags);
    }
 
    /// <summary>
    /// 获取文本对齐
    /// </summary>
    private TextFormatFlags GetFormatFlags(
        HorizontalAlignment align)
    {
        TextFormatFlags flags =
                TextFormatFlags.EndEllipsis |
                TextFormatFlags.VerticalCenter;
 
        switch (align)
        {
            case HorizontalAlignment.Center:
                flags |= TextFormatFlags.HorizontalCenter;
                break;
            case HorizontalAlignment.Right:
                flags |= TextFormatFlags.Right;
                break;
            case HorizontalAlignment.Left:
                flags |= TextFormatFlags.Left;
                break;
        }
 
        return flags;
    }
}

相关的演示代码:

public Form1()
{
    InitializeComponent();
 
    ListViewEx listViewEx1 = new ListViewEx();
    listViewEx1.Icon = Resources.application;
    listViewEx1.IsDrawGridLines = true;
    listViewEx1.IsDrawIcon = true;
    listViewEx1.Location = new Point(0, 0);
    listViewEx1.Name = "listViewEx1";
    listViewEx1.Size = new Size(284, 265);
    listViewEx1.Dock = DockStyle.Fill;
    listViewEx1.FullRowSelect = true;
    listViewEx1.UseCompatibleStateImageBehavior = false;
    listViewEx1.View = View.Details;
    listViewEx1.HeaderStyle = ColumnHeaderStyle.None;
    listViewEx1.Columns.AddRange(new ColumnHeader[] { new ColumnHeader(), new ColumnHeader(), new ColumnHeader() });
 
    for (int i = 1; i <= 3; i++)
    {
        ListViewGroup g = new ListViewGroup("分组" + i.ToString());
        listViewEx1.Groups.Add(g);
        for (int j = 1; j <= 5; j++)
        {
            ListViewItem item = new ListViewItem(j.ToString(), g);
            item.SubItems.Add((i + j).ToString());
            item.SubItems.Add((i * j).ToString());
            listViewEx1.Items.Add(item);
        }
    }
    this.Controls.Add(listViewEx1);
}

DEMO下载

winform ListView应用之分组、重绘图标、网格线 (c# .net winform)的更多相关文章

  1. WinForm中重绘TabControl选项卡标题

    最近开发WinForm频繁使用了TabControl控件,这个控件的选项卡没有BackgroundImage这个属性,那么如何为其各个选项卡添加背景图片呢?(这里说的是每个TabPage的头部,也就是 ...

  2. 重绘Winform窗体

    本文转载自:http://www.cnblogs.com/encoding/p/5603080.html 按照惯例,先来几张样例图(注:为了展示窗口阴影效果,截图范围向外扩展了些,各位凭想象吧). 还 ...

  3. 【原创】重绘winform的GroupBox

    功能:重绘winform的GroupBox,以便调整边框颜色和边框宽度 using System; using System.Collections.Generic; using System.Com ...

  4. Android重绘ListView高度

    Android重绘ListView高度 经常会有这样需求,需要ListView默认将所有的条目显示出来,这就需要外层使用ScrollView,ScrollView里面放置一个重绘高度的ListView ...

  5. windform 重绘Treeview "+-"号图标

    模仿wind系统界面,重绘Treeview + - 号图标 一,首先需要图片 ,用于替换原有的 +-号 二.新建Tree扩展类 TreeViewEx继承TreeView using System; u ...

  6. 使用重绘项美化WinForm中的控件

    如果你觉得项目中的ComboBox.ListBox或其它的Winforms控件不能满足你的显示要求,包括窗体在内很多控件都支持重绘修改显示样式.下面的示例完成对ComBox数据项的重绘,希望能起到抛砖 ...

  7. [DForm]我也来做自定义Winform之另类标题栏重绘

    据说得有楔子 按照惯例,先来几张样例图(注:为了展示窗口阴影效果,截图范围向外扩展了些,各位凭想象吧).                   还要来个序 其实,很多年没写过Winform了,前端时间在 ...

  8. c#winform自定义窗体,重绘标题栏,自定义控件学习

    c#winform自定义窗体,重绘标题栏 虽然现在都在说winform窗体太丑了,但是我也能尽量让桌面应用程序漂亮那么一点点话不多说,先上图 重绘标题栏先将原生窗体设置成无边框,FormBoderSt ...

  9. 『转载』C# winform 中dataGridView的重绘(进度条,虚线,单元格合并等)

    原文转载自:http://hi.baidu.com/suming/item/81e45b1ab9b4585f2a3e2243 最近比较浅的研究了一下dataGridView的重绘,发现里面还是有很多东 ...

随机推荐

  1. WinForm 容器控件

    容器控件: 布局:2个属性:Anchor:锁定位置Dock:填充位置一般Dock是与容器控件配合使用 Panel:就是一个区域,类似于DIV,可以独立布局,还可以让其它控件及容器在它的内部再次布局 F ...

  2. 关于easyUI的模态对话框

    本文版权归博客园和作者吴双本人共同所有,转载和爬虫请注明原文地址.博客园蜗牛cnblogs.com/tdws 会用easyUI的模态对话框会是我们的开发更加简洁,只需下载这个插件,把需要的文件拖到项目 ...

  3. 【C#】妈妈再也不用担心自定义控件如何给特殊类型的属性添加默认值了,附自定义GroupBox一枚

    ------------------更新:201411190903------------------ 经过思考和实践,发现套路中的第1条是不必要的,就是完全可以不用定义一个名为Default+属性名 ...

  4. C# ~ 由 IDisposable 到 GC

    IDisposable 接口 1. 托管资源和非托管资源   ·  托管资源  a.  CLR 控制和管理的内存资源,如程序中在 Heap 上分配的对象.作用域内的变量等:  b.  GC 机制实现自 ...

  5. iOS 阶段学习第九天笔记(内存管理)

    iOS学习(C语言)知识点整理 一.内存管理 1)malloc , 用于申请内存; 结构void *malloc(size_t),需要引用头文件<stdlib.h>:在堆里面申请内存,si ...

  6. Android使用SAX解析XML(4)

    util.java文件如下: package com.hzhi.my_sax; import java.io.IOException; import java.io.InputStream; impo ...

  7. Spring中的事务

    Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource.TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分. DataSo ...

  8. Node.JS模块系统

    1.什么是模块? 为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块系统. 模块是Node.js 应用程序的基本组成部分,文件和模块是一一对应的.换言之,一个 Node.js ...

  9. Linux学习笔记14-权限基础

    权限基础 权限:操作系统限制对资源访问的机制,一般分为读.写.执行.每个文件都拥有特定权限,通过所属用户及所属组来限制哪些用户.组可以对特定文件进行什么样的操作. 每个进程都是以某个用户的身份运行,进 ...

  10. 通过 imagick 让 PHP 生成 PSD 文件缩略图

    第一步.安装ImageMagick 首先需要安装 ImageMagick ,因为 imagick 是一个可以供 PHP 调用 ImageMagick 功能的PHP扩展.(目前最新版本是:ImageMa ...