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

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 3353|回复: 55

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

  [复制链接]
  • TA的每日心情

    2017-9-3 14:58
  • 签到天数: 12 天

    [LV.3]【仗剑天涯】

    佐佑 发表于 2014-10-14 14:46:31 | 显示全部楼层 |阅读模式

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

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

    x
    这份源码是深秋术士提供给我的,但是有很多BUG,我在后来的使用中有了一些改动和优化,而且现在我还一直在用,分享给需要的人吧
    [C#] 纯文本查看 复制代码
    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[i].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[i].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[i].Checked = true;
                }
            }
            else
            {
                for (int i = 0; i < this.Items.Count; i++)
                {
                    this.Items[i].Checked = true;
                }
            }
        }
    
        public void E_Fanxuan()
        {
            if (MyVirtualMode)
            {
                for (int i = 0; i < CurrentCacheItemsSource.Count; i++)
                {
                    if (CurrentCacheItemsSource[i].Checked)
                    {
                        CurrentCacheItemsSource[i].Checked = false;
                    }
                    else
                    {
                        CurrentCacheItemsSource[i].Checked = true;
                    }
                }
            }
            else
            {
                for (int i = 0; i < this.Items.Count; i++)
                {
                    if (this.Items[i].Checked)
                    {
                        this.Items[i].Checked = false;
                    }
                    else
                    {
                        this.Items[i].Checked = true;
                    }
                }
            }
        }
    
        public void E_NoCheckAll()
        {
            if (MyVirtualMode)
            {
                for (int i = 0; i < CurrentCacheItemsSource.Count; i++)
                {
                    if (CurrentCacheItemsSource[i].Checked)
                    {
                        CurrentCacheItemsSource[i].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;
                }
            }
        }
    }
    

    游客,如果您要查看本帖隐藏内容请回复

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

    http://bbs.msdn5.com/thread-1218-1-1.html
    如果失效请联系站长重新分享
    回复

    使用道具 举报

    该用户从未签到

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

    http://bbs.msdn5.com/thread-1218-1-1.html
    如果失效请联系站长重新分享
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    无聊
    2017-3-20 00:16
  • 签到天数: 1 天

    [LV.1]【初入江湖】

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

    http://bbs.msdn5.com/thread-1218-1-1.html
    如果失效请联系站长重新分享
    回复 支持 反对

    使用道具 举报

    该用户从未签到

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

    http://bbs.msdn5.com/thread-1218-1-1.html
    如果失效请联系站长重新分享
    回复 支持 反对

    使用道具 举报

    该用户从未签到

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

    http://bbs.msdn5.com/thread-1218-1-1.html
    如果失效请联系站长重新分享
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2017-3-7 10:46
  • 签到天数: 4 天

    [LV.2]【绿林好汉】

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

    http://bbs.msdn5.com/thread-1218-1-1.html
    如果失效请联系站长重新分享
    回复 支持 反对

    使用道具 举报

    该用户从未签到

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

    http://bbs.msdn5.com/thread-1218-1-1.html
    如果失效请联系站长重新分享
    回复 支持 反对

    使用道具 举报

    该用户从未签到

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

    http://bbs.msdn5.com/thread-1218-1-1.html
    如果失效请联系站长重新分享
    回复 支持 反对

    使用道具 举报

    该用户从未签到

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

    http://bbs.msdn5.com/thread-1218-1-1.html
    如果失效请联系站长重新分享
    回复 支持 反对

    使用道具 举报

    该用户从未签到

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

    http://bbs.msdn5.com/thread-1218-1-1.html
    如果失效请联系站长重新分享
    回复 支持 反对

    使用道具 举报

    *滑动验证:
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    关闭

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

    QQ|Archiver|手机版|小黑屋|玄机论坛   

    GMT+8, 2018-1-16 15:44 , Processed in 0.601860 second(s), 24 queries .

    Powered by Msdn5.com

    © 2014-2015 Msdn5 Inc.

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