C#论坛-玄机论坛-C#论坛-玄机宝盒-玄机类库-C#

 找回密码
 关闭注册

QQ登录

只需一步,快速开始

查看: 12155|回复: 72

[剑走偏锋] Listview重写 开双缓冲 防闪烁 点击表头可以排序

  [复制链接]
佐佑 发表于 2014-10-14 14:46:31 | 显示全部楼层 |阅读模式

玄机论坛-专业的C#交流论坛 交流QQ群: 16885911
如有疑问,请加入官方群询问

您需要 登录 才可以下载或查看,没有帐号?关闭注册

x
这份源码是深秋术士提供给我的,但是有很多BUG,我在后来的使用中有了一些改动和优化,而且现在我还一直在用,分享给需要的人吧
[mw_shl_code=csharp,true]using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Drawing;
using System.Runtime.InteropServices;

public partial class NorListView : ListView
{
    public List<ListViewItem> CurrentCacheItemsSource { get; private set; }
    private string MouseOverCellContent;
    private bool _EnableMouseOverCellContent;

    private int index = 0;
    public event EventHandler Scroll;

    #region SubItems加图标
    [DllImport("user32.dll")]
    static extern int SendMessage(IntPtr hwnd, int msg, int wParam, int lParam);
    [DllImport("user32.dll", SetLastError = true)]
    static extern int SendMessage(IntPtr hwnd, int msg, int wParam, ref LvItem lParam);
    /// <summary>
    /// 扩展风格
    /// </summary>
    private struct LvItem
    {
        public uint mask;//文本+图片
        public int iItem;
        public int iSubItem;
        public uint state;
        public uint stateMask;
        public IntPtr pszText;
        public int cchTextMax;
        public int iImage;
        public IntPtr lParam;
    }
    /// <summary>
    /// 初始化一个扩展listview
    /// </summary>
    /// <param name="lv"></param>
    public static void Extension(Control lv)
    {
        SendMessage(lv.Handle, 0x1000 + 54, 0x0002, 0x0002);
    }
    /// <summary>
    /// 增加一个图片
    /// </summary>
    /// <param name="lv">目标listview</param>
    /// <param name="lie">列</param>
    /// <param name="imgindex">图片index</param>
    public static void Add(ListView lv,int lie,int imgindex)
    {
        int han = lv.Items.Count - 1;
        string txt = lv.Items[han].SubItems[lie].Text;
        //第二列显示图片
        LvItem litem = new LvItem();
        litem.mask = 0x0001 | 0x0002;//文本+图片
        litem.iItem = han;
        litem.iImage = imgindex;
        litem.iSubItem = lie;
        litem.pszText = Marshal.StringToHGlobalAnsi(txt);
        SendMessage(lv.Handle, 0x1000 + 6, 0, ref litem);
    }

   
    #endregion

    protected override void OnDrawItem(DrawListViewItemEventArgs e)
    {
        ListViewItem item = this.TopItem;
        if (item != null && item.Index != index)
        {
            index = item.Index;
            if (Scroll != null)
            {
                Scroll(this, null);
            }
        }
        e.DrawDefault = true;
        base.OnDrawItem(e);
    }

    protected override void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e)
    {
        e.DrawDefault = true;
        base.OnDrawColumnHeader(e);
    }

    protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e)
    {
        e.DrawDefault = true;
        base.OnDrawSubItem(e);
    }

    public bool EnableMouseOverCellContent
    {
        get { return _EnableMouseOverCellContent; }
        set
        {
            _EnableMouseOverCellContent = value;
            if (value)
            {
                this.MouseUp += new MouseEventHandler(MyListView_MouseUp);
            }
            else
            {
                this.MouseUp -= new MouseEventHandler(MyListView_MouseUp);
            }
        }
    }
    public bool MyVirtualMode
    {
        get { return VirtualMode; }
        set
        {
            VirtualMode = value;
            if (value)
            {
                this.RetrieveVirtualItem += new RetrieveVirtualItemEventHandler(NorListView_RetrieveVirtualItem);
                this.ColumnClick -= new ColumnClickEventHandler(EListView_ColumnClick);
                this.OwnerDraw = true;
                this.DrawColumnHeader += new DrawListViewColumnHeaderEventHandler(NorListView_DrawColumnHeader);
                this.DrawItem += new DrawListViewItemEventHandler(NorListView_DrawItem);
                this.MouseClick += new MouseEventHandler(NorListView_MouseClick);
                this.MouseDoubleClick += new MouseEventHandler(NorListView_MouseDoubleClick);
            }
            else
            {
                this.RetrieveVirtualItem -= new RetrieveVirtualItemEventHandler(NorListView_RetrieveVirtualItem);
                this.ColumnClick += new ColumnClickEventHandler(EListView_ColumnClick);
                this.OwnerDraw = false;
                this.DrawItem -= new DrawListViewItemEventHandler(NorListView_DrawItem);
                this.MouseClick -= new MouseEventHandler(NorListView_MouseClick);
                this.MouseDoubleClick -= new MouseEventHandler(NorListView_MouseDoubleClick);
            }
        }
    }

    public NorListView()
    {
        //InitializeComponent();
        this.OwnerDraw = true;
        ImageList il = new ImageList();
        il.ImageSize = new Size(5, 16);
        this.SmallImageList = il;
        this.GridLines = true;
        this.MouseOverCellContent = "";
        this.EnableMouseOverCellContent = false;
        this.ListViewItemSorter = new ListViewColumnSorter();
        this.CurrentCacheItemsSource = new List<ListViewItem>();
        //this.ColumnClick += new ColumnClickEventHandler(EListView_ColumnClick);
        // 开启双缓冲
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
        this.SetStyle(ControlStyles.EnableNotifyMessage, true);
    }

    protected override void OnNotifyMessage(Message m)
    {
        if (m.Msg != 0x14)
        {
            base.OnNotifyMessage(m);
        }
    }

    public void ReSet(IList<ListViewItem> l)
    {
        this.CurrentCacheItemsSource.Clear();
        this.CurrentCacheItemsSource.AddRange(l);
        this.VirtualListSize = this.CurrentCacheItemsSource.Count;
    }

    private void NorListView_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
    {
        if (this.CurrentCacheItemsSource == null || this.CurrentCacheItemsSource.Count == 0)
        {
            return;
        }
        ListViewItem lv = this.CurrentCacheItemsSource[e.ItemIndex];
        e.Item = lv;
    }

    private void NorListView_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
    {
        e.DrawDefault = true;
    }

    private void NorListView_DrawItem(object sender, DrawListViewItemEventArgs e)
    {
        e.DrawDefault = true;
        if (!e.Item.Checked)
        {
            e.Item.Checked = true;
            e.Item.Checked = false;
        }
    }

    private void NorListView_MouseClick(object sender, MouseEventArgs e)
    {
        ListView lv = (ListView)sender;
        ListViewItem lvi = lv.GetItemAt(e.X, e.Y);
        if (lvi != null)
        {
            if (e.X < (lvi.Bounds.Left + 16))
            {
                lvi.Checked = !lvi.Checked;
                lv.Invalidate(lvi.Bounds);
            }
        }
    }

    private void NorListView_MouseDoubleClick(object sender, MouseEventArgs e)
    {
        ListView lv = (ListView)sender;
        ListViewItem lvi = lv.GetItemAt(e.X, e.Y);
        if (lvi != null)
            lv.Invalidate(lvi.Bounds);
    }

    private void MyListView_MouseUp(object sender, MouseEventArgs e)
    {
        if (e.Button == System.Windows.Forms.MouseButtons.Right)
        {
            int currentcellindex = 0;
            if (this.SelectedItems.Count > 0)
            {
                for (int i = 0; i < this.SelectedItems[0].SubItems.Count; i++)
                {
                    if (i == this.SelectedItems[0].SubItems.Count - 1)
                    {
                        currentcellindex = i;
                        break;
                    }

                    if (e.X >= this.SelectedItems[0].SubItems.Bounds.Left && e.X < this.SelectedItems[0].SubItems[i + 1].Bounds.Left)
                    {
                        currentcellindex = i;
                        break;
                    }
                }

                MouseOverCellContent = this.SelectedItems[0].SubItems[currentcellindex].Text;
            }
        }
    }

    /// <summary>获得鼠标所在当前单元格的内容</summary>
    public string GetMouseOverCellContent()
    {
        return MouseOverCellContent;
    }

    /// <summary>设置列文本</summary>
    public void E_SetColumnText(string Key, int ColumnIndex, string Text, Color ForceColor)
    {
        if (this.Items.ContainsKey(Key))
        {
            try
            {
                this.Items[Key].SubItems[ColumnIndex].Text = Text;
                this.Items[Key].SubItems[ColumnIndex].ForeColor = ForceColor;
            }
            catch
            { }
        }
    }

    /// <summary>设置行背景色</summary>
    public void E_SetBackColor(string Key, Color BackColor)
    {
        if (this.Items.ContainsKey(Key))
        {
            for (int i = 0; i < this.Items[Key].SubItems.Count; i++)
            {
                this.Items[Key].SubItems.BackColor = BackColor;
            }
        }
    }

    /// <summary>设置行键</summary>
    public void E_SetItemName(string OldKey, string NewKey)
    {
        if (this.Items.ContainsKey(OldKey))
        {
            this.Items[OldKey].Name = NewKey;
        }
    }

    /// <summary>选中整行</summary>
    public void E_SelectItem(string Key)
    {
        if (this.Items.ContainsKey(Key))
        {
            this.Items[Key].Selected = true;
            this.Select();
            this.Items[Key].Focused = true;
        }
    }

    /// <summary>移除行</summary>
    public void E_RemoveItem(string Key)
    {
        try
        {
            if (this.Items.ContainsKey(Key))
            {
                this.Items.RemoveByKey(Key);
            }
        }
        catch
        { }
    }

    /// <summary>Check所有行</summary>
    public void E_CheckAll()
    {
        if (MyVirtualMode)
        {
            for (int i = 0; i < CurrentCacheItemsSource.Count; i++)
            {
                CurrentCacheItemsSource.Checked = true;
            }
        }
        else
        {
            for (int i = 0; i < this.Items.Count; i++)
            {
                this.Items.Checked = true;
            }
        }
    }

    public void E_Fanxuan()
    {
        if (MyVirtualMode)
        {
            for (int i = 0; i < CurrentCacheItemsSource.Count; i++)
            {
                if (CurrentCacheItemsSource.Checked)
                {
                    CurrentCacheItemsSource.Checked = false;
                }
                else
                {
                    CurrentCacheItemsSource.Checked = true;
                }
            }
        }
        else
        {
            for (int i = 0; i < this.Items.Count; i++)
            {
                if (this.Items.Checked)
                {
                    this.Items.Checked = false;
                }
                else
                {
                    this.Items.Checked = true;
                }
            }
        }
    }

    public void E_NoCheckAll()
    {
        if (MyVirtualMode)
        {
            for (int i = 0; i < CurrentCacheItemsSource.Count; i++)
            {
                if (CurrentCacheItemsSource.Checked)
                {
                    CurrentCacheItemsSource.Checked = false;
                }
            }
        }
        else
        {
            foreach (ListViewItem item in this.CheckedItems)
            {
                item.Checked = false;
            }
        }
    }

    public void E_Insert(ListViewItem item)
    {
        if (this.VirtualMode)
        {
            CurrentCacheItemsSource.Add(item);
            this.VirtualListSize = this.CurrentCacheItemsSource.Count;
        }
        else
        {
            this.Items.Add(item);
        }
    }

    public void E_RemoveAll()
    {
        if (this.VirtualMode)
        {
            CurrentCacheItemsSource.Clear();
            this.VirtualListSize = 0;
        }
        else
        {
            this.Items.Clear();
        }
    }

    public void E_Remove(int Index, int Count)
    {
        if (this.VirtualMode)
        {
            CurrentCacheItemsSource.RemoveRange(Index, Count);
            this.VirtualListSize = this.CurrentCacheItemsSource.Count;
        }
    }

    private void EListView_ColumnClick(object sender, ColumnClickEventArgs e)
    {
        if (e.Column == ((ListViewColumnSorter)this.ListViewItemSorter).SortColumn)
        {
            // 重新设置此列的排序方法.
            if ((this.ListViewItemSorter as ListViewColumnSorter).Order == SortOrder.Ascending)
            {
                (this.ListViewItemSorter as ListViewColumnSorter).Order = SortOrder.Descending;
            }
            else
            {
                (this.ListViewItemSorter as ListViewColumnSorter).Order = SortOrder.Ascending;
            }
        }
        else
        {
            // 设置排序列,默认为正向排序
            (this.ListViewItemSorter as ListViewColumnSorter).SortColumn = e.Column;
            (this.ListViewItemSorter as ListViewColumnSorter).Order = SortOrder.Ascending;
        }
        this.Sort();
    }

    public void SetSort(int Column, SortOrder Order)
    {
        (this.ListViewItemSorter as ListViewColumnSorter).Order = Order;
        this.Sort();
    }

    public class ListViewColumnSorter : IComparer
    {
        /**/
        /// <summary>
        /// 指定按照哪个列排序
        /// </summary>
        private int ColumnToSort;
        /**/
        /// <summary>
        /// 指定排序的方式
        /// </summary>
        private SortOrder OrderOfSort;
        /**/
        /// <summary>
        /// 声明CaseInsensitiveComparer类对象,
        /// 参见ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/cpref/html/frlrfSystemCollectionsCaseInsensitiveComparerClassTopic.htm
        /// </summary>
        private CaseInsensitiveComparer ObjectCompare;

        /**/
        /// <summary>
        /// 构造函数
        /// </summary>
        public ListViewColumnSorter()
        {
            // 默认按第一列排序
            ColumnToSort = 0;

            // 排序方式为不排序
            OrderOfSort = SortOrder.None;

            // 初始化CaseInsensitiveComparer类对象
            ObjectCompare = new CaseInsensitiveComparer();
        }

        /**/
        /// <summary>
        /// 重写IComparer接口.
        /// </summary>
        /// <param name="x">要比较的第一个对象</param>
        /// <param name="y">要比较的第二个对象</param>
        /// <returns>比较的结果.如果相等返回0,如果x大于y返回1,如果x小于y返回-1</returns>
        public int Compare(object x, object y)
        {
            int compareResult;
            ListViewItem listviewX, listviewY;

            // 将比较对象转换为ListViewItem对象
            listviewX = (ListViewItem)x;
            listviewY = (ListViewItem)y;

            // 比较
            int intox, intoy;
            string xvalue = listviewX.SubItems[ColumnToSort].Text;
            string yvalue = listviewY.SubItems[ColumnToSort].Text;

            if (int.TryParse(xvalue, out intox) && int.TryParse(yvalue, out intoy))
            {
                compareResult = intox.CompareTo(intoy);
            }
            else
            {
                compareResult = ObjectCompare.Compare(xvalue, yvalue);
            }

            // 根据上面的比较结果返回正确的比较结果
            if (OrderOfSort == SortOrder.Ascending)
            {
                // 因为是正序排序,所以直接返回结果
                return compareResult;
            }
            else if (OrderOfSort == SortOrder.Descending)
            {
                // 如果是反序排序,所以要取负值再返回
                return (-compareResult);
            }
            else
            {
                // 如果相等返回0
                return 0;
            }
        }

        /**/
        /// <summary>
        /// 获取或设置按照哪一列排序.
        /// </summary>
        public int SortColumn
        {
            set
            {
                ColumnToSort = value;
            }
            get
            {
                return ColumnToSort;
            }
        }

        /**/
        /// <summary>
        /// 获取或设置排序方式.
        /// </summary>
        public SortOrder Order
        {
            set
            {
                OrderOfSort = value;
            }
            get
            {
                return OrderOfSort;
            }
        }
    }
}
[/mw_shl_code]
游客,如果您要查看本帖隐藏内容请回复

玄机论坛-专业的C#交流论坛 交流QQ群: 16885911
帖子内网盘失效后请使用下面地址

http://bbs.msdn5.com/forum.php?mod=viewthread&tid=1218
如果失效请联系站长重新分享
回复

使用道具 举报

dxzyboy 发表于 2014-10-15 21:34:34 | 显示全部楼层
好东西。收藏下来。。。
玄机论坛-专业的C#交流论坛 交流QQ群: 16885911
帖子内网盘失效后请使用下面地址

http://bbs.msdn5.com/forum.php?mod=viewthread&tid=1218
如果失效请联系站长重新分享
回复 支持 反对

使用道具 举报

sillypgm 发表于 2014-10-17 12:28:40 | 显示全部楼层
感谢分享,还没用过这个东西。
玄机论坛-专业的C#交流论坛 交流QQ群: 16885911
帖子内网盘失效后请使用下面地址

http://bbs.msdn5.com/forum.php?mod=viewthread&tid=1218
如果失效请联系站长重新分享
回复 支持 反对

使用道具 举报

shaome 发表于 2014-10-17 14:25:30 | 显示全部楼层
haodongxi,shoucle
玄机论坛-专业的C#交流论坛 交流QQ群: 16885911
帖子内网盘失效后请使用下面地址

http://bbs.msdn5.com/forum.php?mod=viewthread&tid=1218
如果失效请联系站长重新分享
回复 支持 反对

使用道具 举报

盼你有罪 发表于 2014-10-18 13:46:05 | 显示全部楼层
学习学习
玄机论坛-专业的C#交流论坛 交流QQ群: 16885911
帖子内网盘失效后请使用下面地址

http://bbs.msdn5.com/forum.php?mod=viewthread&tid=1218
如果失效请联系站长重新分享
回复

使用道具 举报

inghot 发表于 2014-10-22 16:20:25 | 显示全部楼层
好东西,谢稿分享。
玄机论坛-专业的C#交流论坛 交流QQ群: 16885911
帖子内网盘失效后请使用下面地址

http://bbs.msdn5.com/forum.php?mod=viewthread&tid=1218
如果失效请联系站长重新分享
回复 支持 反对

使用道具 举报

Blogger 发表于 2014-10-23 17:25:43 | 显示全部楼层
好资料啊。谢谢
玄机论坛-专业的C#交流论坛 交流QQ群: 16885911
帖子内网盘失效后请使用下面地址

http://bbs.msdn5.com/forum.php?mod=viewthread&tid=1218
如果失效请联系站长重新分享
回复 支持 反对

使用道具 举报

Magic 发表于 2014-10-24 09:35:33 | 显示全部楼层
好东西,学习了
玄机论坛-专业的C#交流论坛 交流QQ群: 16885911
帖子内网盘失效后请使用下面地址

http://bbs.msdn5.com/forum.php?mod=viewthread&tid=1218
如果失效请联系站长重新分享
回复 支持 反对

使用道具 举报

xjm 发表于 2014-11-1 23:26:46 | 显示全部楼层
保存了,谢谢
玄机论坛-专业的C#交流论坛 交流QQ群: 16885911
帖子内网盘失效后请使用下面地址

http://bbs.msdn5.com/forum.php?mod=viewthread&tid=1218
如果失效请联系站长重新分享
回复 支持 反对

使用道具 举报

mmgx2015 发表于 2014-11-3 13:20:47 | 显示全部楼层
回复一下看看该怎么使用
玄机论坛-专业的C#交流论坛 交流QQ群: 16885911
帖子内网盘失效后请使用下面地址

http://bbs.msdn5.com/forum.php?mod=viewthread&tid=1218
如果失效请联系站长重新分享
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 关闭注册

本版积分规则

关闭

站长推荐上一条 /2 下一条

QQ|玄机论坛

GMT+8, 2020-10-26 06:01 , Processed in 0.211378 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表