winform ListView应用之分组、重绘图标、网格线 (c# .net winform)

最近在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下载

时间: 2024-07-29 12:25:49

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

WinForm中重绘TabControl选项卡标题

最近开发WinForm频繁使用了TabControl控件,这个控件的选项卡没有BackgroundImage这个属性,那么如何为其各个选项卡添加背景图片呢?(这里说的是每个TabPage的头部,也就是标题,不是工作区域.) 最开始用到TabControl的时候,我的每个选项卡是写死的,而后由于项目需求又动态添加了TabControl并生成各个选项卡,而两次我都要重绘其标题,因此在这里把我当时两种情形下重绘的方法通过一个例子一起分享出来. 首先先在窗体拖个Tabcontrol控件,然后更改了其Al

winform重绘窗体成圆角(网上借鉴)

winform做圆角窗体: 1 //重绘窗体为圆角 2 private void frmMain_Paint(object sender, PaintEventArgs e) 3 { 4 #region 5 6 List<Point> list = new List<Point>(); 7 int width = this.Width; 8 int height = this.Height; 9 10 #region 四个圆角 11 12 //左上 13 list.Add(new

【原创】重绘winform的GroupBox

功能:重绘winform的GroupBox,以便调整边框颜色和边框宽度 using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Linq; using System.Text; using System.Windows.Forms; using System.Drawing.Drawing2D

android Listview下滑,自动加载数据.修改多处地方,去除重绘listvew,防止闪烁

感谢其他大神的的源码支持 我仅在此源码上进行修改以及注释. 使用方法: //设置加载分页数据监听 loadingListView.setOnLoadMoreListener(new OnLoadMoreListener() { public void onLoadMore() { if(page<3){ }else{ loadingListView.onLoadMoreComplete();//移除加载更多布局,加载完成 loadingListView.setIsEnable(false); /

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

据说得有楔子 按照惯例,先来几张样例图(注:为了展示窗口阴影效果,截图范围向外扩展了些,各位凭想象吧).                   还要来个序 其实,很多年没写过Winform了,前端时间在重构我们公司自己的呼叫中心系统,突然就觉得客户端好丑好丑,对于我这种强迫症晚期患者来说,界面不好看都不知道怎么写代码的,简直就是种折磨,还是满清十大酷刑级别那种. 很多人推荐WPF,不过个人对WPF没啥感觉,而且据说也无法支持2.0,还是采用Winform技术来搞吧. 终于第一节 做Winform皮

winform重绘

1.重绘文字#多行文字a.先定义一个矩形 Rectangle p1 = new Rectangle(10, 0, 200, this.Height); Rectangle p2 = new Rectangle(210, 0, 200, this.Height); Rectangle p3 = new Rectangle(410, 0, 100, this.Height); b.在矩形中写入文字 TextRenderer.DrawText(g,name,Font,p1,ForeColor,Text

WinForm中按钮等控件的背景渐变色重绘

注:brush通过起止坐标来控制重绘范围及方向.比如从上到下渐变时,brush第二个Point参数是左下角坐标. 1 private void PaintGradientBackground(Button btn) 2 { 3 Bitmap newGradientBackImg = new Bitmap(btn.Width, btn.Height); 4 LinearGradientBrush brush = new LinearGradientBrush(new PointF(0, 0), n

窗体皮肤实现 - 重绘窗体非客户区(三)

窗体边框基本的绘制和控制完成,在第二篇中主要遗留的问题. 标题区域图标和按钮没绘制 缩放时客户区显示有问题 解决完下面的问题,皮肤处理基本完整.大致的效果GIF GIF中TShape的颜色表现有些问题,实际是正常的. 绘制标题区域内容 获取标题有效区域 绘制窗体图标 绘制按钮 绘制标题 标题区域主要考虑窗体是否在最大化状态,最大化后实际的标题绘制区域会有变化.可以通过 IsZoomed 或 GetWindowLong(Handle, GWL_STYLE) and WS_MAXIMIZE = WS

css的重排与重绘

一直在做pc页面的部分,由于网速快,看上去css的写法并没有什么影响所以对css的要求也没怎么注意过,最近在做一些手机端的东西,发现真的差好多,特别是再搭配上js效果时一些延迟更是让人接受不了.在这个快餐的时代,确实导致手机端更具有市场,搭乘地铁的时间变成人们浏览新闻,玩游戏,甚至是购物的时间,此时用户应用的设备多数会是手机,而手机与电脑比起来最大的差距就是网速,这对开发者的要求也就提高了,如何能够加快加载减少响应时间就变成了开发者永恒不变的话题.目前虽然有很多的前辈们已经针对这个现状提出了很多