我们在使用Office Excel的时候,有很多时候需要冻结行或者列。这时,Excel会在冻结的行列和非冻结的区域之间绘制上一条明显的黑线。如下图:

(图1)

WinForm下的DataGridView控件也能实现类似的冻结行或者列的功能(参见:http://msdn.microsoft.com/zh-cn/library/28e9w2e1(VS.85).aspx) ,但是呢,DataGridView控件默认不会在冻结列或者行的分界处绘制一个明显的分界线,这样的话,最终用户很难注意到当前有列或者行是冻结的。如下图所示:你能很快的找到那一列是Freeze的么?

(图2)

正是因为如此,我们如果能做出类似Excel的效果,就可以大大提高数据的可读性。

通常,我们如果想在现有的控件上多画点什么,就会去Override OnPaint方法,然后加入自己的OwnerDraw逻辑,但是呢在DataGridView上有一些困难:

1.如何确定冻结分界线的位置 
2.如何保证分界线不会绘制到ScrollBar上 
研究了一下,我们可以借用DataGridView提供的CellPainting方法。在DataGridView绘制每一个Cell的时候判断当前Cell是否是分界线所在的位置,然后进行绘制。最终做出的效果如下图:

(图3)

以下是DataGridView控件扩展源代码:

public class DataGridViewEx : DataGridView
{
    protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e)
    {
        base.OnCellPainting(e);
 
        //
        // Paints the Frozen line
        //
        int lastFreezeColumnIndex = GetDisplayColumnFrozenLineIndex();
        int lastFreezeRowIndex = GetDisplayRowFrozenLineIndex();
 
        bool drawRowLine = lastFreezeRowIndex != -1 && lastFreezeRowIndex == e.RowIndex;
        bool drawColumLine = lastFreezeColumnIndex != -1 && lastFreezeColumnIndex == e.ColumnIndex;
 
        if (drawRowLine || drawColumLine)
        {
            e.Paint(e.ClipBounds, e.PaintParts);
 
            if (drawColumLine)
            {
                e.Graphics.DrawLine(Pens.Black,
                    e.CellBounds.Right - 1, e.CellBounds.Top,
                    e.CellBounds.Right - 1, this.ClientRectangle.Bottom);
            }
            if (drawRowLine)
            {
                e.Graphics.DrawLine(Pens.Black,
                    e.CellBounds.Left, e.CellBounds.Bottom - 1,
                    e.CellBounds.Right, e.CellBounds.Bottom - 1);
            }
 
            e.Handled = true;
        }
    }
 
    private int GetDisplayColumnFrozenLineIndex()
    {
        int lastFreezeColumnIndex = -1;
        for (int i = 0; i < this.ColumnCount; i++)
        {
            DataGridViewColumn column = this.Columns[i];
            if (column.Visible && column.Frozen)
            {
                lastFreezeColumnIndex = i;
            }
            else if (!column.Frozen)
            {
                return lastFreezeColumnIndex;
            }
        }
        return lastFreezeColumnIndex;
    }
 
    private int GetDisplayRowFrozenLineIndex()
    {
        int lastFreezeRowIndex = -1;
        for (int i = 0; i < this.RowCount; i++)
        {
            DataGridViewRow row = this.Rows[i];
            if (row.Visible && row.Frozen)
            {
                lastFreezeRowIndex = i;
            }
            else if (!row.Frozen)
            {
                return lastFreezeRowIndex;
            }
        }
        return lastFreezeRowIndex;
 
    }
}

在DataGridView控件中实现冻结列分界线的更多相关文章

  1. 实现DataGridView控件中CheckBox列的使用

    最近做WindowsForms程序,使用DataGridView控件时,加了一列做选择用,发现CheckBox不能选中.搜索后,要实现DataGridView的CellContentClick事件,将 ...

  2. 在DataGridView控件中加入ComboBox下拉列表框的实现

    在DataGridView控件中加入ComboBox下拉列表框的实现 转自:http://www.cnblogs.com/luqingfei/archive/2007/03/28/691372.htm ...

  3. 在DataGridView控件中验证数据输入

    实现效果: 知识运用: DataGridView控件的公共事件CellValidating //将System.Windows.Forms.DataGridViewCellValidatingEven ...

  4. DataGridView控件中添加ComboBox下拉列表框的实现

    //ComboBox控件拖放到DataGridView控件的某个位置 //添加年龄下拉框 private void BindAge() { //我这里添加的是静态数据,一般都是从数据库读出来的,这里就 ...

  5. 在DataGridView控件中显示图片

    实现效果: 知识运用: DataGridView控件的DataSource属性 实现代码: private void Form1_Load(object sender, EventArgs e) { ...

  6. 禁止DataGridView控件中添加和删除行

    实现效果: 知识运用: DataGridView控件的AllowUserToAddRows AllowUserDeleteRows和ReadOnly属性 实现代码: private void btn_ ...

  7. 在DataGridView控件中启用换行

    实现效果: 知识运用: DataGridView控件公共属性DefaultCellStyle的WrapMode属性 public DataGridViewTriState WrapMode {  ge ...

  8. 设置DataGridView控件中字体的样式

    实现效果: 知识运用: DataGridView控件的公共属性DefaultCellStyle的Font属性 public Font Font  {get;set;} //获取或设置应用与DataGr ...

  9. 如何在winform DataGridView控件的DataGridViewButtonColumn按钮列中禁用按钮

    原文:http://msdn.microsoft.com/en-us/library/ms171619(v=vs.85).ASPX public class DataGridViewDisableBu ...

随机推荐

  1. A. Nearest Common Ancestors

    A. Nearest Common Ancestors Time Limit: 1000ms Case Time Limit: 1000ms Memory Limit: 10000KB   64-bi ...

  2. 九度oj 题目1160:放苹果

    题目描述: 把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法. 输入: 第一行是测试数据的数目t(0 <= t ...

  3. MySQL5.7 MTS work线程stack

    复制现象是,slave线程状态正常,但是sql 线程不应用,所以delay越来越大,查看复制状态 mysql> show slave status\G********************** ...

  4. UVa——1600Patrol Robot(A*或普通BFS)

    Patrol Robot Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Descripti ...

  5. USACO 2.1 The Castle

    题目大意:给你一个城堡让你求有多少房间,最大房间有多大,敲掉一堵墙后最大的房间有多大,敲掉那座墙 思路:比较恶心的bfs题,反正就是bfs使劲敲 /*{ ID:a4298442 PROB:castle ...

  6. BestCoder Round #29 1003 (hdu 5172) GTY's gay friends [线段树 判不同 预处理 好题]

    传送门 GTY's gay friends Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Ot ...

  7. grequests----golang的requests库

    github.com/levigross/grequests: A Go "clone" of the great and famous Requests library 特点: ...

  8. Golang中的panic和recover(捕获异常)

    func panic(interface{})和func recover() interface{}是Golang中用于错误处理的两个函数. panic的作用就是抛出一条错误信息,从它的参数类型可以看 ...

  9. raspi串口、python串口模块pyserial

    一.安装 1.下载软件包pyserial-2.7.tar.gz   网址:https://pypi.python.org/pypi/pyserial 2.8uftp上传至/usr/local/src/ ...

  10. 当传入数据只有一个时mybatis中<if>判断会出现There is no getter for property named 'subjectId' in 'class java.lang.Intege

    用"_parameter"代替当前参数 正确: <select id="selectSubjectByPId" parameterType="j ...