在ListView控件中可视地指示排序

时间:2009-06-25 01:11:49

标签: .net winforms

在XP和Vista的Windows资源管理器中,当ListView处于“详细信息”模式时按列排序时,列的背景将突出显示以指示列正在排序。排序方向的箭头也显示在列标题中。在您自己的Windows窗体应用程序中实现这些效果的最佳实践是什么?

1 个答案:

答案 0 :(得分:3)

此方法模拟“Windows XP”样式的选择。 Vista和Win7使用ListViews的扩展功能,但是.NET中没有(但是?)。如果需要,可以使用Interop完成。

以下是如何做到这一点:

  1. 创建一个包含以下图像的ImageList:0:空,1:“向上”和2:“向下”

    • 将此ImageList分配给ListView.SmallImageList属性
    • 每次将项目添加到ListView中时,请确保其UseItemStyleForSubItems设置为“false”
    • 将排序代码添加到您的应用程序,其中描述了here
    • 在您刚刚添加的代码中,使用以下代码替换ColumnClick处理程序(此处的ListView实例称为“_List”):

      void _List_ColumnClick(object sender,ColumnClickEventArgs e){     _List.SuspendLayout();     if(e.Column == lvwColumnSorter.SortColumn){//先前排序的列将被翻转         if(lvwColumnSorter.Order == SortOrder.Ascending){             lvwColumnSorter.Order = SortOrder.Descending;         } else {             lvwColumnSorter.Order = SortOrder.Ascending;         }     } else {//新列将被排序         _List.Columns [lvwColumnSorter.SortColumn] .ImageIndex = 0;         foreach(_List.Items中的ListViewItem lvi){             lvi.SubItems [lvwColumnSorter.SortColumn] .BackColor = SystemColors.Window;         }         lvwColumnSorter.SortColumn = e.Column;         lvwColumnSorter.Order = SortOrder.Ascending;     }     _List.Sort();     _List.Columns [e.Column] .ImageIndex = lvwColumnSorter.Order == SortOrder.Ascending? 1:2;     foreach(_List.Items中的ListViewItem lvi){         lvi.SubItems [e.Column] .BackColor = SystemColors.Info; //这是用于跟踪的颜色     }     _List.ResumeLayout(); }


  2. 编辑:

    以下是互操作方法:

        [DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, uint message, UIntPtr wParam, IntPtr lParam);
        [DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, uint message, UIntPtr wParam, ref HDITEM lParam);
    
        public enum WM {
            LVM_FIRST = 0x1000,      // ListView messages
            // ...
            LVM_GETHEADER = LVM_FIRST + 31,
            // ...
            HDM_FIRST = 0x1200,      // Header messages
            // ...
            HDM_SETITEM = HDM_FIRST + 12,
            // ...
            HDM_SETFOCUSEDITEM = HDM_FIRST + 28,
        }
        public enum HDI {
            HDI_WIDTH = 0x0001,
            HDI_HEIGHT = HDI_WIDTH,
            HDI_TEXT = 0x0002,
            HDI_FORMAT = 0x0004,
            HDI_LPARAM = 0x0008,
            HDI_BITMAP = 0x0010,
            HDI_IMAGE = 0x0020,
            HDI_DI_SETITEM = 0x0040,
            HDI_ORDER = 0x0080,
            HDI_FILTER = 0x0100,
            HDI_STATE = 0x0200
        }
        public enum HDF {
            HDF_LEFT                = 0x0000,
            HDF_RIGHT               = 0x0001,
            HDF_CENTER              = 0x0002,
            HDF_JUSTIFYMASK         = 0x0003,
            HDF_RTLREADING          = 0x0004,
            HDF_BITMAP              = 0x2000,
            HDF_STRING              = 0x4000,
            HDF_OWNERDRAW           = 0x8000,
            HDF_IMAGE               = 0x0800,
            HDF_BITMAP_ON_RIGHT     = 0x1000,
            HDF_SORTUP              = 0x0400,
            HDF_SORTDOWN            = 0x0200,
            HDF_CHECKBOX            = 0x0040,
            HDF_CHECKED             = 0x0080,
            HDF_FIXEDWIDTH          = 0x0100,
            HDF_SPLITBUTTON      = 0x1000000
        }
        [StructLayout(LayoutKind.Sequential)]
        public struct HDITEM {
            public uint mask;
            public int cxy;
            public String pszText;
            public IntPtr hbm;
            public int cchTextMax;
            public int fmt;
            public IntPtr lParam;
            public int iImage;
            public int iOrder;
            public uint type;
            public IntPtr pvFilter; // this is void*
            public uint state;
        }
    
    
        void _List_ColumnClick(object sender, ColumnClickEventArgs e) {
            _List.SuspendLayout();
            HDITEM hdi = new HDITEM();
            hdi.mask = (uint)HDI.HDI_FORMAT;
            hdi.fmt = (int)HDF.HDF_STRING;
            IntPtr hHeader = (IntPtr)SendMessage(_List.Handle, (uint)WM.LVM_GETHEADER, (UIntPtr)0, (IntPtr)0);
            if (e.Column == lvwColumnSorter.SortColumn) { // the column previously sorted will be flipped
                if (lvwColumnSorter.Order == SortOrder.Ascending) {
                    lvwColumnSorter.Order = SortOrder.Descending;
                } else {
                    lvwColumnSorter.Order = SortOrder.Ascending;
                }
            } else {    // new column will be sorted
                SendMessage((IntPtr)hHeader, (uint)WM.HDM_SETITEM, (UIntPtr)lvwColumnSorter.SortColumn, ref hdi);
                foreach (ListViewItem lvi in _List.Items) {
                    lvi.SubItems[lvwColumnSorter.SortColumn].BackColor = SystemColors.Window;
                }
                lvwColumnSorter.SortColumn = e.Column;
                lvwColumnSorter.Order = SortOrder.Ascending;
            }
            _List.Sort();
            hdi.fmt |= (lvwColumnSorter.Order == SortOrder.Ascending ? (int)HDF.HDF_SORTDOWN : (int)HDF.HDF_SORTUP);
            SendMessage((IntPtr)hHeader, (uint)WM.HDM_SETITEM, (UIntPtr)e.Column, ref hdi);
            foreach (ListViewItem lvi in _List.Items) {
                lvi.SubItems[e.Column].BackColor = SystemColors.Info; // this is the color used for tracking
            }
            _List.ResumeLayout();
        }