📄 listviewex.cs
字号:
using System;
using System.Windows.Forms;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Drawing.Drawing2D;
using System.Resources;
using System.Drawing.Text;
using System.Reflection;
using System.Collections;
using System.ComponentModel;
using UtilityLibrary.Win32;
using UtilityLibrary.General;
namespace UtilityLibrary.WinControls
{
#region Enumerations
public enum SortedListViewFormatType
{
String,
Numeric,
Date,
Custom
}
public enum SortedListViewSortDirection
{
Ascending,
Descending
}
#endregion
#region Delegates
public delegate int ListSortEvent(ListViewItem item1, ListViewItem item2);
#endregion
#region Helper Classes
internal class HeaderIconHelper
{
#region Class Variables
int headerIndex;
int iconIndex;
#endregion
#region Constructor
public HeaderIconHelper(int HeaderIndex, int IconIndex)
{
headerIndex = HeaderIndex;
iconIndex = IconIndex;
}
#endregion
#region Properties
public int HeaderIndex
{
set { headerIndex = value; }
get { return headerIndex; }
}
public int IconIndex
{
set { iconIndex = value; }
get { return iconIndex; }
}
#endregion
}
internal class RowSorterHelper
{
#region Class Variables
int columnIndex;
SortedListViewFormatType format;
ListSortEvent sortEvent = null;
#endregion
#region Constructors
public RowSorterHelper(int columnIndex, SortedListViewFormatType format)
{
this.columnIndex = columnIndex;
this.format = format;
}
public RowSorterHelper(int columnIndex, SortedListViewFormatType format, ListSortEvent sortEvent)
{
this.columnIndex = columnIndex;
this.format = format;
this.sortEvent = sortEvent;
}
#endregion
#region Properties
public int ColumnIndex
{
set { columnIndex = value; }
get { return columnIndex; }
}
public SortedListViewFormatType Format
{
set { format = value; }
get { return format; }
}
public ListSortEvent SortEvent
{
set { sortEvent = value; }
get { return sortEvent; }
}
#endregion
}
internal class HeaderHook : System.Windows.Forms.NativeWindow
{
#region Class Variables
ListViewEx listView = null;
#endregion
#region Constructors
public HeaderHook(ListViewEx lv)
{
listView = lv;
}
#endregion
#region Overrides
protected override void WndProc(ref Message m)
{
int message = m.Msg;
Point mousePos = new Point(0,0);
if ( message == (int)Msg.WM_LBUTTONDOWN ||
message == (int)Msg.WM_LBUTTONUP)
{
mousePos = WindowsAPI.GetPointFromLPARAM((int)m.LParam);
listView.LastMousePosition = mousePos;
}
if ( message == (int)Msg.WM_LBUTTONDOWN && listView.Tracking == false )
{
for (int i = 0; i < listView.Columns.Count; i++ )
{
Rectangle rc = listView.GetHeaderItemRect(i);
if ( rc.Contains(mousePos))
{
listView.PressedHeaderItem = i;
WindowsAPI.InvalidateRect(m.HWnd, IntPtr.Zero, 0);
break;
}
}
}
if ( message == (int)Msg.WM_LBUTTONUP && listView.Tracking == false )
{
listView.PressedHeaderItem = -1;
for (int i = 0; i < listView.Columns.Count; i++ )
{
Rectangle rc = listView.GetHeaderItemRect(i);
if ( rc.Contains(mousePos))
{
listView.LastSortedColumn = i;
if ( listView.Sorting == SortOrder.None)
{
// We will set the sorting to descending
// because the default sorting already took place
// and default sorting is ascending
listView.Sorting = SortOrder.Descending;
}
else
{
if ( listView.Sorting == SortOrder.Ascending )
listView.Sorting = SortOrder.Descending;
else
listView.Sorting = SortOrder.Ascending;
}
break;
}
}
// update item
WindowsAPI.InvalidateRect(m.HWnd, IntPtr.Zero, 0);
}
base.WndProc(ref m);
}
#endregion
}
public class CompareListItems : IComparer
{
#region Class Variables
ListViewEx listView = null;
#endregion
#region Constructors
public CompareListItems(ListViewEx lv)
{
listView = lv;
}
#endregion
#region Methods
public int Compare(object obj1, object obj2)
{
ListViewItem item1 = (ListViewItem)obj1;
ListViewItem item2 = (ListViewItem)obj2;
RowSorterHelper rs = listView.GetRowSorterHelper();
string string1 = item1.Text;
string string2 = item2.Text;
int result = 0;
if ( listView.LastSortedColumn != 0 )
{
// adjust the objets if we have to sort subitems
string1 = item1.SubItems[listView.LastSortedColumn].Text;
string2 = item2.SubItems[listView.LastSortedColumn].Text;
Debug.Assert(obj1 != null && obj2 != null);
}
if ( rs != null )
{
if ( rs.Format == SortedListViewFormatType.String)
result = CompareStrings(string1, string2, listView.Sorting);
else if ( rs.Format == SortedListViewFormatType.Numeric )
result = CompareNumbers(string1, string2, listView.Sorting);
else if ( rs.Format == SortedListViewFormatType.Date )
result = CompareDates(string1, string2, listView.Sorting);
else if ( rs.Format == SortedListViewFormatType.Custom)
{
if ( rs.SortEvent != null )
{
result = rs.SortEvent((ListViewItem)obj1, (ListViewItem)obj2);
if ( listView.Sorting == SortOrder.Descending )
result *= -1;
}
}
}
else if ( rs == null )
{
// Consider column as strings
result = CompareStrings(string1, string2, listView.Sorting);
}
return result;
}
#endregion
#region Implementation
int CompareStrings(string string1, string string2, SortOrder sortOrder)
{
int result = string.Compare(string1, string2);
if ( sortOrder == SortOrder.Descending)
result *= -1;
return result;
}
int CompareNumbers(string string1, string string2, SortOrder sortOrder)
{
// Parse the object as if the were floating number that will take
// care of both cases: integers and floats
// -- exceptions will be thrown if they cannot be parsed
float float1 = float.Parse(string1);
float float2 = float.Parse(string2);
int result = float1.CompareTo(float2);
if ( sortOrder == SortOrder.Descending)
result *= -1;
return result;
}
int CompareDates(string string1, string string2, SortOrder sortOrder)
{
// Parse the object as if the were floating number that will take
// care of both cases: integers and floats
// -- exceptions will be thrown if they cannot be parsed
DateTime date1 = DateTime.Parse(string1);
DateTime date2 = DateTime.Parse(string2);
int result = DateTime.Compare(date1, date2);
if ( sortOrder == SortOrder.Descending)
result *= -1;
return result;
}
#endregion
}
#endregion
/// <summary>
/// Summary description for SortableListView.
/// </summary>
[ToolboxItem(false)]
public class ListViewEx : ListView
{
#region Class Variables
// Keeps track of the header control handle
// so that we can distinguish between notification and
// reflected messages
IntPtr hHeader = IntPtr.Zero;
// Keep track of what column was sorted last
int lastSortedColumn = 0;
bool setInitialSortColumn = false;
HeaderHook headerHook = null;
bool tracking = false;
int pressedHeaderItem = -1;
// To keep track if the cursor
// hit a header divider
Point lastMousePosition;
// ImageList for the check boxes
// in case user decide to use checkboxes
ImageList checkBoxesImageList;
// Header Icons
ImageList headerImageList;
ArrayList headerIconsList = new ArrayList();
// Sorting helper
ArrayList rowSorterList = new ArrayList();
// We only support small 16x16 icons
const int IMAGE_WIDTH = 16;
const int TEXT_TO_ARROW_GAP = 15;
const int ARROW_WIDTH = 12;
const int BUFFER_SIZE = 1024;
int counter = 0;
#endregion
#region Constructors
public ListViewEx()
{
SetStyle(ControlStyles.UserPaint, false);
// Control needs to have full row select and detail
// view enable otherwise it won't behave as intended
FullRowSelect = true;
View = View.Details;
HeaderStyle = ColumnHeaderStyle.Nonclickable;
InitializeCheckBoxesImageList();
ListViewItemSorter = new CompareListItems(this);
}
private void InitializeCheckBoxesImageList()
{
checkBoxesImageList = new ImageList();
checkBoxesImageList.ImageSize = new Size(16, 16);
Assembly thisAssembly = Assembly.GetAssembly(Type.GetType("UtilityLibrary.WinControls.ListViewEx"));
ResourceManager rm = new ResourceManager("UtilityLibrary.Resources.SortedListView", thisAssembly);
Bitmap checkBox = (Bitmap)rm.GetObject("CheckBox");
checkBox.MakeTransparent(Color.FromArgb(0, 128, 128));
checkBoxesImageList.Images.AddStrip(checkBox);
}
#endregion
#region Overrides
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
// Now that the list control has been created
// get a hold of the header control so that we can
// subclass it
// -- Header control always has a control ID equal zero
hHeader = WindowsAPI.GetDlgItem(Handle, 0);
Debug.Assert(hHeader != IntPtr.Zero, "Fail to get Header Control Windows Handle...");
headerHook = new HeaderHook(this);
headerHook.AssignHandle(hHeader);
}
protected override void WndProc(ref Message message)
{
base.WndProc(ref message);
switch (message.Msg)
{
case (int)Msg.WM_ERASEBKGND:
IntPtr hDC = (IntPtr)message.WParam;
PaintBackground(hDC);
break;
// Notification messages come from the header
case (int)Msg.WM_NOTIFY:
NMHDR nm1 = (NMHDR) message.GetLParam(typeof(NMHDR));
switch(nm1.code)
{
case (int)NotificationMessages.NM_CUSTOMDRAW:
Debug.Write("CUSTOM DRAWING");
Debug.WriteLine(counter++);
NotifyHeaderCustomDraw(ref message);
break;
case (int)HeaderControlNotifications.HDN_BEGINTRACKW:
Tracking = true;
break;
case (int)HeaderControlNotifications.HDN_ENDTRACKW:
Tracking = false;
break;
default:
break;
}
break;
// Reflected Messages come from the list itself
case (int)ReflectedMessages.OCM_NOTIFY:
NMHDR nm2 = (NMHDR) message.GetLParam(typeof(NMHDR));
switch (nm2.code)
{
case (int)NotificationMessages.NM_CUSTOMDRAW:
NotifyListCustomDraw(ref message);
break;
case (int)ListViewNotifications.LVN_GETDISPINFOW:
Debug.WriteLine("List View GetDispInfo Notifications");
break;
default:
break;
}
break;
// Default
default:
break;
}
}
#endregion
#region Properties
internal int LastSortedColumn
{
set { lastSortedColumn = value; Invalidate(); }
get { return lastSortedColumn; }
}
public int InitialSortedColumn
{
set
{
if ( setInitialSortColumn == false )
{
setInitialSortColumn = true;
lastSortedColumn = value;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -