##更新历史:


##DataGridView


在WinForm中,DataGridView是常用列表显示控件,也是相对复杂的一个控件,对于经常做管理软件的开发者,DataGridView也是打交道最多的一个。 这里记录本人在实际开发中使用DataGridView的一些备忘。

###调整单元格样式后排序或其他方式使控件刷新而丢失样式的问题


很多软件都有这么一个需求:对于异常数据或特殊数据进行高亮显示。
如一个超限软件,对于超限率不同的检测车辆进行不同的颜色显示;又如某设备管理软件,对于即将维保、年检的设备进行黄色提示,对于已过维保期的设备进行红色提示等等。
本人在做的时候,都是在绑定数据后,循环遍历一次数据,判断某列的值是否符合某种标准,否则给予标注。

以前做法:

void BindData()
{
    //BindData...

    for(int i = 0; i < dataGridView1.Rows.Length; i++)
    {
        if(dataGridView.Rows[i].Cells["停用标识"].Value.ToString() == "启用")
        {
            dataGridView.Rows[i].Cells["停用标识"].Style.BackColor = Color.Red;
        }
    }
}

但随后发现如果点击排序,都会丢失之前设置的样式。 对于这种不是很影响功能的问题,当初我都不怎么在意,或者对于不是很需要排序功能的直接禁止其排序。(这种思想是不是很不好……)

但问题终归是问题,最后还是得解决。 注册CellFormatting事件,在其中进行判断。

代码如下:

void dataGridView1_CellFormatting(object sender, 
    DataGridViewCellFormattingEventArgs e)
{
    if(e.ColumnIndex = 7 && e.Value.ToString() == "启用")
    {
        e.CellStyle.BackColor = Color.Red;
    }
}

##ListView


相较DataGridView而言,ListView在WinForm开发中比较灵活,列表可以实现,带图标的排列也没问题,而且做一些效果也是不错。ListView显然没有DataGirdView封装的那么”严实”,也正是因为这个问题,很多看似简单的功能在ListView中实现很难。

###关于ListView排序的众多问题


最近需要在软件中增加FTP功能,说是简单的功能,但是做起来也遇到了不少问题。主要问题就是目录浏览的问题,如何从FTP返回的列表中分割出大小、修改时间等也是当初没有想到的。而在列表展示上使用ListView控件的主要原因就是ListView控件”添加”数据比较自然,而DataGridView更多的是”绑定”数据。
随后发现ListView没有排序功能。
其实排序功能还是有的,只不过需要自己给定一个比较器。

listView1.ListViewItemSorter = XXXComparer.Instance(XXXComparer : IComparer)

ListViewSort

这就是我FTP的窗口。只显示了文件名、大小和修改时间,文件名中目录使用[目录名]的方式展示,文件名的排序方式按道理上来讲应该是向上、目录、文件这种顺序。大小和修改时间就不用多说了。
这时候,问题就出来了:ListView的项(SubItem)没有数据类型一说。
对此,给我ListViewSubItem增加了一个强类型的ListViewSubItem:

/// <summary>
/// 强类型ListViewSubItem
/// </summary>
/// <typeparam name="T"></typeparam>
public class ListViewTypeSubItem<T> : ListViewItem.ListViewSubItem
{
    public ListViewTypeSubItem()
    {
        ValueType = typeof(T);
    }

    public Type ValueType { get; set; }

    public T Value { get; set; }
}

当然,这个所谓的强类型还是有一定的问题。暂时这么着吧。
有了强类型的 ListViewSubItem 那么给ListView赋值就要有相应的修改。

foreach (var file in files)
{
    lvi = new ListViewItem(file.IsDirectory ? string.Format("[{0}]", file.Name) : file.Name);

    size = new ListViewTypeSubItem<long>();
    size.Text = file.Size.ToString("N0");
    size.Value = file.Size;
    lvi.SubItems.Add(size);

    date = new ListViewTypeSubItem<DateTime>();
    date.Text = file.CreateTime.ToString("yyyy-MM-dd HH:mm");
    date.Value = file.CreateTime;
    lvi.SubItems.Add(date);

    lvi.Tag = file.IsDirectory ? FileTypeEnum.Directory : FileTypeEnum.File;

    lvFtpFile.Items.Add(lvi);
}

当然,重要的比较器还没有写。这里列出我写的比较器,其中应该有点问题,因为当初没有想让他能点两次。也就是说没有想让他支持点一次是asc,再点一次就是desc。本来只是想做个排序,让大小和修改时间逆序排,而文件名就按我上面说的规则排列。最后需求有所变动。
说了半天,列出我的比较器:

/// <summary>
/// ListViewItem自定义排序
/// 对long类型和DateTime类型进行处理(DESC)
/// 对于字符串,目录排在文件上面,向上排在最上边
/// </summary>
public class ListViewItemComparer : IComparer
{
    private static int col;
    private static bool isDesc = false;

    public ListViewItemComparer(int column)
    {
        col = column;
    }

    public int Compare(object x, object y)
    {
        int result = 0;
        var sub = ((ListViewItem)x).SubItems[col];
        if (sub is ListViewTypeSubItem<long>)
        {
            var sub_x = ((ListViewItem)x).SubItems[col] as ListViewTypeSubItem<long>;
            var sub_y = ((ListViewItem)y).SubItems[col] as ListViewTypeSubItem<long>;
            if (sub_x.Value > sub_y.Value)
            {
                result = 1;
            }
            else if (sub_x.Value == sub_y.Value)
            {
                result = 0;
            }
            else
            {
                result = -1;
            }
        }
        else if (sub is ListViewTypeSubItem<DateTime>)
        {
            var sub_x = ((ListViewItem)x).SubItems[col] as ListViewTypeSubItem<DateTime>;
            var sub_y = ((ListViewItem)y).SubItems[col] as ListViewTypeSubItem<DateTime>;

            result = DateTime.Compare(sub_y.Value, sub_x.Value);
        }
        else
        {
            string sub_x = ((ListViewItem)x).SubItems[col].Text;
            string sub_y = ((ListViewItem)y).SubItems[col].Text;
            if ((sub_x[0] == '[' && sub_x[sub_x.Length - 1] == ']') &&
            (sub_y[0] != '[' || sub_y[sub_y.Length - 1] != ']'))
            {
                return -1;
            }
            else
            {
                result = string.Compare(sub_x, sub_y);
            }
        }

        var lvi_x = (ListViewItem)x;
        var lvi_y = (ListViewItem)y;

        if (lvi_x.Text == "[..]")
        {
            return -1;
        }

        //if (lvi_y.Text == "[..]")
        //{
        //   return isDesc ? 1 : -1;
        //}

        return isDesc ? result : result == 0 ? 0 : result == 1 ? -1 : 1;
    }

    public static ListViewItemComparer Sort(int column = 0)
    {
        isDesc = !isDesc;

        return new ListViewItemComparer(column);
    }
}

应该从代码中更能感觉到曾经改过的样子。
自我感觉上面的return isDesc ? result : result == 0 ? 0 : result == 1 ? -1 : 1;一定会有人说。哈哈。



blog comments powered by Disqus

Published

2012-11-22

Tags