Adding icons in the headers for sorting acts weird on Win7 x64 in C # net 3.5

I spent a couple of hours trying to solve where the problem is with adding icons to the listView title. The code below works fine on Win 7 32Bit and Windows XP 32Bit. However, I now changed the machine to Win 7 x64, and it was hell with code.

Below code works when sorting is called in a column, it adds an up or down icon depending on the order and resets any icons in the header in other columns. However, on Win7 x64 it does not change the up / down icon (it just always uses the first one) and never clears the icons from other columns (when sorting is taken out of it).

public class ListViewColumnSorter : IComparer {
    [StructLayout(LayoutKind.Sequential)] public struct HDITEM {
        public Int32 mask;
        public Int32 cxy;
        [MarshalAs(UnmanagedType.LPTStr)] public String pszText;
        public IntPtr hbm;
        public Int32 cchTextMax;
        public Int32 fmt;
        public Int32 lParam;
        public Int32 iImage;
        public Int32 iOrder;
    } ;
    public const Int32 HDI_FORMAT = 0x0004;
    public const Int32 HDI_IMAGE = 0x0020;
    public const Int32 HDI_DI_SETITEM = 0x0040;
    public const Int32 HDF_LEFT = 0x0000;
    public const Int32 HDF_RIGHT = 0x0001;
    public const Int32 HDF_CENTER = 0x0002;
    public const Int32 HDF_JUSTIFYMASK = 0x0003;
    public const Int32 HDF_STRING = 0x4000;
    public const Int32 HDF_BITMAP_ON_RIGHT = 0x1000;
    public const Int32 HDF_IMAGE = 0x0800;
    //Parameters for ListViews
    public const Int32 LVM_FIRST = 0x1000;
    public const Int32 LVM_GETHEADER = LVM_FIRST + 31;
    //Messages for ListView-Headers
    public const Int32 HDM_FIRST = 0x1200;
    public const Int32 HDM_SETIMAGELIST = HDM_FIRST + 8;
    public const Int32 HDM_GETIMAGELIST = HDM_FIRST + 9;
    public const Int32 HDM_GETITEM = HDM_FIRST + 11;
    public const Int32 HDM_SETITEM = HDM_FIRST + 12;
    [DllImport("user32", EntryPoint = "SendMessage")] private static extern IntPtr SendMessageINT(IntPtr Handle, Int32 msg, IntPtr wParam, IntPtr lParam);
    [DllImport("user32", EntryPoint = "SendMessage")] private static extern IntPtr SendMessageITEM(IntPtr Handle, Int32 msg, IntPtr wParam, ref HDITEM lParam);
    public static IntPtr SendMessage(IntPtr Handle, Int32 msg, IntPtr wParam, IntPtr lParam) {
        return SendMessageINT(Handle, msg, wParam, lParam);
    }
    public static IntPtr SendMessage(IntPtr Handle, Int32 msg, IntPtr wParam, ref HDITEM lParam) {
        return SendMessageITEM(Handle, msg, wParam, ref lParam);
    }
    /// <summary>
    /// Specifies the column to be sorted
    /// </summary>
    private int ColumnToSort;
    /// <summary>
    /// Specifies the order in which to sort (i.e. 'Ascending').
    /// </summary>
    private SortOrder OrderOfSort;
    /// <summary>
    /// Case insensitive comparer object
    /// </summary>
    private CaseInsensitiveComparer ObjectCompare;
    /// <summary>
    /// Class constructor.  Initializes various elements
    /// </summary>
    public ListViewColumnSorter() {
        // Initialize the column to '0'
        ColumnToSort = 0;
        // Initialize the sort order to 'none'
        OrderOfSort = SortOrder.None;
        // Initialize the CaseInsensitiveComparer object
        ObjectCompare = new CaseInsensitiveComparer();
    }
    /// <summary>
    /// This method is inherited from the IComparer interface.  It compares the two objects passed using a case insensitive comparison.
    /// </summary>
    /// <param name="x">First object to be compared</param>
    /// <param name="y">Second object to be compared</param>
    /// <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns>
    public int Compare(object x, object y) {
        int compareResult;
        ListViewItem listviewX = (ListViewItem) x;
        ListViewItem listviewY = (ListViewItem) y;
        string s1 = listviewX.SubItems.Count > ColumnToSort ? listviewX.SubItems[ColumnToSort].Text : String.Empty;
        string s2 = listviewY.SubItems.Count > ColumnToSort ? listviewY.SubItems[ColumnToSort].Text : String.Empty;
        int i1;
        int i2;
        DateTime date1;
        DateTime date2;
        if (int.TryParse(s1, out i1) && int.TryParse(s2, out i2)) {
            compareResult = ObjectCompare.Compare(i1, i2);
        } else if (DateTime.TryParse(s1, out date1) && DateTime.TryParse(s2, out date2)) {
            compareResult = ObjectCompare.Compare(date1, date2);
        } else {
            compareResult = ObjectCompare.Compare(s1, s2);
        }
        // Compare the two items
        //        try {
        //    // Parse the two objects passed as a parameter as a DateTime.
        //    System.DateTime firstDate = DateTime.Parse();
        //    System.DateTime secondDate = DateTime.Parse(((ListViewItem)y).SubItems[col].Text);
        //    // Compare the two dates.
        //    returnVal = DateTime.Compare(firstDate, secondDate);
        //}
        //// If neither compared object has a valid date format, compare
        //// as a string.
        //catch 
        //{
        //    // Compare the two items as a string.
        //    returnVal = String.Compare(((ListViewItem)x).SubItems[col].Text,
        //                ((ListViewItem)y).SubItems[col].Text);
        //}
        //try {
        // } catch {
        //    compareResult = 0; 
        // } 
        // Calculate correct return value based on object comparison
        if (OrderOfSort == SortOrder.Ascending) {
            // Ascending sort is selected, return normal result of compare operation
            return compareResult;
        } else if (OrderOfSort == SortOrder.Descending) {
            // Descending sort is selected, return negative result of compare operation
            return (-compareResult);
        } else {
            // Return '0' to indicate they are equal
            return 0;
        }
    }
    /// <summary>
    /// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0').
    /// </summary>
    public int SortColumn {
        set { ColumnToSort = value; }
        get { return ColumnToSort; }
    }
    /// <summary>
    /// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending').
    /// </summary>
    public SortOrder Order {
        set { OrderOfSort = value; }
        get { return OrderOfSort; }
    }
    public static void columnClick(ListView varListView, ref ListViewColumnSorter lvwColumnSorter, object sender, ColumnClickEventArgs e) {
        ListViewHelper.enableDoubleBuffer(varListView);
        if (e.Column == lvwColumnSorter.SortColumn) {
            if (lvwColumnSorter.Order == SortOrder.Ascending) {
                lvwColumnSorter.Order = SortOrder.Descending;
            } else {
                lvwColumnSorter.Order = SortOrder.Ascending;
            }
        } else {
            lvwColumnSorter.SortColumn = e.Column;
            lvwColumnSorter.Order = SortOrder.Ascending;
        }
        varListView.Sort();
    }
    public static void columnClick(ListView varListView, ref ListViewColumnSorter lvwColumnSorter, object sender, ColumnClickEventArgs e, ImageList headerImages) {
        //get list view header
        IntPtr hHeader = SendMessage(varListView.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);
        SendMessage(hHeader, HDM_SETIMAGELIST, IntPtr.Zero, headerImages.Handle);
        SortOrder Order = SortOrder.Descending;
        //format icons
        HDITEM hd = new HDITEM {
                                   mask = HDI_IMAGE | HDI_FORMAT
                               };
        for (int i = 0; i < varListView.Columns.Count; i++) {
        //    if (i != e.Column) {
              hd.fmt = HDF_STRING;
              hd.iImage = -1;
                SendMessage(hHeader, HDM_SETITEM, new IntPtr(i), ref hd);
        //    }
        }
        hd.fmt = HDF_LEFT | HDF_STRING | HDF_BITMAP_ON_RIGHT;
        ListViewHelper.enableDoubleBuffer(varListView);
        if (Order != SortOrder.None) {
            hd.fmt |= HDF_IMAGE;
        }
        if (e.Column == lvwColumnSorter.SortColumn) {
            if (lvwColumnSorter.Order == SortOrder.Ascending) {
                hd.iImage = 0;
                lvwColumnSorter.Order = SortOrder.Descending;

            } else {
                hd.iImage = 1;
                lvwColumnSorter.Order = SortOrder.Ascending;
            }
        } else {
             hd.iImage = 1;
            lvwColumnSorter.SortColumn = e.Column;
            lvwColumnSorter.Order = SortOrder.Ascending;
        }
        SendMessage(hHeader, HDM_SETITEM, new IntPtr(e.Column), ref hd);
        varListView.Sort();
    }
}

I use it in the ColumnClick event:

    private void listViewKlienci_ColumnClick(object sender, ColumnClickEventArgs e) {
        ListViewColumnSorter.columnClick(listViewKlienci, ref lvwColumnSorterKlienci, sender, e, headerIcons);
    }

where headerIcons is an ImageList that contains several icons.

I also add:

private ListViewColumnSorter lvwColumnSorterKlienci = new ListViewColumnSorter();

MainForm :

listViewKlienci.ListViewItemSorter = lvwColumnSorterKlienci;

, ? x64:/

, - .

+3
1

public Int32 lParam; public IntPtr lParam;

, Int32, x64 8 , 4 , , . , , lParam, lParam iImage; iImage, iOrder, iOrder, .

, , , .

+2

Source: https://habr.com/ru/post/1733774/


All Articles