提供数据绑定和排序功能的ListView完全解决方案
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.Reflection;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
using System.Data ;
namespace ListViewEx
{
#region Enumerations
public enum SortedFormatType
{
String,
Numeric,
Date,
Custom
}
public enum SortedDirection
{
Ascending,
Descending
}
#endregion
#region 事件处理定义...
public delegate void ListViewExEventHandler(object sender, ListViewExEventArgs e);
/// <summary>
///在生成Listview 事件 需要的自定义参数。
/// </summary>
public class ListViewExEventArgs : EventArgs
{
private string mFiledName;
private string mSubItemText;
public ListViewExEventArgs(string pFieldName,string pSubItemText)
{
mFiledName = pFieldName;
mSubItemText = pSubItemText;
}
#region Public 属性 ...
public string SubItemText
{
get
{
return mSubItemText;
}
set
{
mSubItemText=value;
}
}
#endregion Public 属性 ...
}
#endregion 事件处理定义...
/// <summary>
/// 继承ListView 并增加数据绑定和排序的功能
/// </summary>
[ToolboxItemFilter("System.Windows.Forms")]
[ToolboxBitmap(typeof(ListViewEx),"ListViewEx.bmp")]
public class ListViewEx : ListView
{
private DataSet mDataSouce;
private int mKeyIndex = -1 ;
private string mKeyName = "ID";
private SortColumnType[] mColType;
private ListViewSortManager mSortManager;
private int mMaxRowCount = 1000;
#region 事件处理相关...
private ListViewExEventHandler mBeforAddCell;
public event ListViewExEventHandler BeforAddCell
{
add
{
mBeforAddCell += value;
}
remove
{
mBeforAddCell -= value;
}
}
private void FireBeforAddCell(ListViewExEventArgs e)
{
if (mBeforAddCell!= null)
{
// 调用相应的委托代理
mBeforAddCell(this, e);
}
}
#endregion 事件处理相关...
public ListViewEx()
{
FullRowSelect = true;
View = View.Details;
this.CheckBoxes = true;
}
//绑定DataSet
public DataSet DataSouce
{
set
{
mDataSouce = value;
refresh();
}
}
#region 创建 ListView 的表头和子项...
private void refresh()
{
Debug.Assert(mDataSouce!=null,"显示ListView","显示ListView的时候不能设置一个空的DataSet!");
createColumns() ;
createListItem();
//增加排序的处理
mSortManager = new ListViewSortManager(this,mColType);
}
//创建 List Item
private void createListItem()
{
DataTable dt = mDataSouce.Tables[0];
if(this.Items.Count>0)
this.Items.Clear();
int colCount = dt.Columns.Count;
int curRowIndex = 0;
foreach(DataRow dr in dt.Rows)
{
//目前设置最大值是1000,翻页处理以后再添加
if(curRowIndex > MaxRowCount)
break;
//先增加Key 值列
int itemIndex = 0;
if( mKeyIndex ==0)
{
itemIndex =1;
}
string cellText = dr[itemIndex].ToString();
ListViewExEventArgs arg = new ListViewExEventArgs( dt.Columns[itemIndex].ColumnName,cellText);
FireBeforAddCell(arg);
ListViewItem item = new ListViewItem(arg.SubItemText,0);
//把Table 的行存在Item 的tag 属性中
item.Tag = dr;
for(int i=itemIndex ; i< mKeyIndex;i++)
{
cellText = dr[i].ToString();
arg = new ListViewExEventArgs( dt.Columns[i].ColumnName,cellText);
FireBeforAddCell(arg);
item.SubItems.Add(arg.SubItemText);
}
for(int i=mKeyIndex +1;i<colCount ;i++)
{
cellText = dr[i].ToString();
arg = new ListViewExEventArgs( dt.Columns[i].ColumnName,cellText);
FireBeforAddCell(arg);
item.SubItems.Add(arg.SubItemText);
}
curRowIndex ++;
this.Items.Add(item) ;
}
}
//创建ListView的表头
private void createColumns()
{
DataTable dt = mDataSouce.Tables[0];
if(Columns.Count > 0)
Columns.Clear();
int i = 0;
mColType = new SortColumnType[dt.Columns.Count];
foreach(DataColumn dc in dt.Columns)
{
//HorizontalAlignment.Left
//得到该Table 中是否有内置的Key Index 并得到它
if(i!=mKeyIndex)
{
if(dc.ColumnName.ToUpper() == mKeyName)
{
//this.Columns.Add(dc.Caption, 0,getAlignment(dc,i));
mKeyIndex = i;
}
else
{
this.Columns.Add(dc.Caption,100,getAlignment(dc,i));
}
}
i++;
}
}
//得到列的文本的对齐方式
private HorizontalAlignment getAlignment(DataColumn pDc,int pColIndex)
{
switch(pDc.GetType().Name)
{
case "String":
mColType[pColIndex] = SortColumnType.Text ;
return HorizontalAlignment.Left;
case "Int16" :
case "Int32" :
case "Decimal":
mColType[pColIndex] = SortColumnType.Number;
return HorizontalAlignment.Right;
case "DateTime" :
mColType[pColIndex] = SortColumnType.DateTime;
return HorizontalAlignment.Left;
default:
mColType[pColIndex] = SortColumnType.Text ;
return HorizontalAlignment.Left;
}
}
#endregion 创建 ListView 的表头和子项...
#region Public 属性 ...
public int KeyIndex
{
get
{
return mKeyIndex;
}
set
{
mKeyIndex = value;
}
}
public string KeyName
{
get
{
return mKeyName;
}
set
{
mKeyName = value;
}
}
public int MaxRowCount
{
get
{
return mMaxRowCount;
}
set
{
mMaxRowCount = value;
}
}
#endregion Public 属性 ...
}
#region ListViewSortManager ...
enum SortColumnType
{
Text,
Number,
DateTime
}
/// <summary>
/// 继承IComparer接口,提供两个文本之间的比较方法
/// </summary>
class ListViewTextSort: IComparer
{
private SortColumnType mType;
private Int32 mColumn;
private Boolean mAscending;
public SortColumnType CompareType
{
set
{
mType = value;
}
}
public ListViewTextSort(Int32 sortColumn, Boolean ascending)
{
mColumn = sortColumn;
mAscending = ascending;
}
/// <summary>
/// 实现IComparer.Compare
/// </summary>
/// <param name="lhs">比较的第一个对象</param>
/// <param name="rhs">比较的第二个对象</param>
/// <returns> 如果lhs 小于 rhs那么小于零,否则大于零,或者等于零</returns>
public Int32 Compare(Object lhs, Object rhs)
{
ListViewItem lhsLvi = lhs as ListViewItem;
ListViewItem rhsLvi = rhs as ListViewItem;
if(lhsLvi == null || rhsLvi == null)
return 0;
ListViewItem.ListViewSubItemCollection lhsItems = lhsLvi.SubItems;
ListViewItem.ListViewSubItemCollection rhsItems = rhsLvi.SubItems;
String lhsText = (lhsItems.Count > mColumn) ? lhsItems[mColumn].Text : String.Empty;
String rhsText = (rhsItems.Count > mColumn) ? rhsItems[mColumn].Text : String.Empty;
Int32 result = 0;
if(lhsText.Length == 0 || rhsText.Length == 0)
result = lhsText.CompareTo(rhsText);
else
result = OnCompare(lhsText, rhsText);
if(!mAscending)
result = -result;
return result;
}
/// <summary>
/// 覆盖进行特别类型的比较
/// </summary>
/// <param name="lhs">比较的第一个对象</param>
/// <param name="rhs">比较的第二个对象</param>
/// <returns> 如果lhs 小于 rhs那么小于零,否则大于零,或者等于零</returns>
protected virtual Int32 OnCompare(String lhs, String rhs)
{
switch(mType)
{
case SortColumnType.Text :
return String.Compare(lhs, rhs, false);
case SortColumnType.Number :
Double result = Double.Parse(lhs) - Double.Parse(rhs);
if(result > 0)
return 1;
else if(result < 0)
return -1;
else
return 0;
case SortColumnType.DateTime :
return DateTime.Parse(lhs).CompareTo(DateTime.Parse(rhs));
default :
return String.Compare(lhs, rhs, false);
}
}
}
/// <summary>
/// 和ListViewEx分离,实现列排序的管理
/// </summary>
class ListViewSortManager
{
private Int32 mColumn;
private SortOrder mSortOrder;
private ListViewEx mList;
private SortColumnType[] mComparers;
private ImageList mImgList;
/// <param name="list">管理列排序的ListViewEx对象</param>
/// <param name="comparers">对应每一列排序的类型</param>
public ListViewSortManager(ListViewEx list, SortColumnType[] comparers)
{
mColumn = -1;
mSortOrder = SortOrder.None;
mList = list;
mComparers = comparers;
mImgList = new ImageList();
mImgList.ImageSize = new Size(8, 8);
mImgList.TransparentColor = System.Drawing.Color.Magenta;
mImgList.Images.Add(GetArrowBitmap(ListSortDirection.Ascending));
mImgList.Images.Add(GetArrowBitmap(ListSortDirection.Descending));
SetHeaderImageList(mList, mImgList);
list.ColumnClick += new ColumnClickEventHandler(ColumnClick);
}
/// <summary>
/// 当前排序的列的Index
/// </summary>
public Int32 Column
{
get { return mColumn; }
}
/// <summary>
/// 当前排序的方式
/// </summary>
public SortOrder SortOrder
{
get { return mSortOrder; }
}
/// <summary>
/// 排序行
/// </summary>
public void Sort(Int32 column)
{
SortOrder order = SortOrder.Ascending;
if(column == mColumn)
order = (mSortOrder == SortOrder.Ascending) ? SortOrder.Descending : SortOrder.Ascending;
Sort(column, order);
}
public void Sort(Int32 column, SortOrder order)
{
if(column < 0 || column >= mComparers.Length)
throw new IndexOutOfRangeException();
if(column != mColumn)
{
ShowHeaderIcon(mList, mColumn, SortOrder.None);
mColumn = column;
}
ShowHeaderIcon(mList, mColumn, order);
mSortOrder = order;
if(order != SortOrder.None)
{
ListViewTextSort comp = new ListViewTextSort(mColumn, order == SortOrder.Ascending);//(ListViewTextSort) Activator.CreateInstance(mComparers[mColumn], new Object[] { mColumn, order == SortOrder.Ascending } );
comp.CompareType = mComparers[mColumn];
mList.ListViewItemSorter = comp;
}
}
//当Click ListViewEx列标题时,得到它的事件,并进行排序的处理
private void ColumnClick(object sender, ColumnClickEventArgs e)
{
this.Sort(e.Column);
}
#region Graphics
//画向下或者向上的方向箭头
Bitmap GetArrowBitmap(ListSortDirection type)
{
Bitmap bmp = new Bitmap(8, 8);
Graphics gfx = Graphics.FromImage(bmp);
Pen lightPen = SystemPens.ControlLightLight;
Pen shadowPen = SystemPens.ControlDark;
gfx.FillRectangle(System.Drawing.Brushes.Magenta, 0, 0, 8, 8);
if(type == ListSortDirection.Ascending)
{
gfx.DrawLine(lightPen, 0, 7, 7, 7);
gfx.DrawLine(lightPen, 7, 7, 4, 0);
gfx.DrawLine(shadowPen, 3, 0, 0, 7);
}
else if(type == ListSortDirection.Descending)
{
gfx.DrawLine(lightPen, 4, 7, 7, 0);
gfx.DrawLine(shadowPen, 3, 7, 0, 0);
gfx.DrawLine(shadowPen, 0, 0, 7, 0);
}
gfx.Dispose();
return bmp;
}
#region WIndows32 API...
[StructLayout(LayoutKind.Sequential)]
private 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;
};
[DllImport("user32")]
static extern IntPtr SendMessage(IntPtr Handle, Int32 msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32", EntryPoint="SendMessage")]
static extern IntPtr SendMessage2(IntPtr Handle, Int32 msg, IntPtr wParam, ref HDITEM lParam);
const Int32 HDI_WIDTH = 0x0001;
const Int32 HDI_HEIGHT = HDI_WIDTH;
const Int32 HDI_TEXT = 0x0002;
const Int32 HDI_FORMAT = 0x0004;
const Int32 HDI_LPARAM = 0x0008;
const Int32 HDI_BITMAP = 0x0010;
const Int32 HDI_IMAGE = 0x0020;
const Int32 HDI_DI_SETITEM = 0x0040;
const Int32 HDI_ORDER = 0x0080;
const Int32 HDI_FILTER = 0x0100; // 0x0500
const Int32 HDF_LEFT = 0x0000;
const Int32 HDF_RIGHT = 0x0001;
const Int32 HDF_CENTER = 0x0002;
const Int32 HDF_JUSTIFYMASK = 0x0003;
const Int32 HDF_RTLREADING = 0x0004;
const Int32 HDF_OWNERDRAW = 0x8000;
const Int32 HDF_STRING = 0x4000;
const Int32 HDF_BITMAP = 0x2000;
const Int32 HDF_BITMAP_ON_RIGHT = 0x1000;
const Int32 HDF_IMAGE = 0x0800;
const Int32 HDF_SORTUP = 0x0400; // 0x0501
const Int32 HDF_SORTDOWN = 0x0200; // 0x0501
const Int32 LVM_FIRST = 0x1000; // List 消息
const Int32 LVM_GETHEADER = LVM_FIRST + 31;
const Int32 HDM_FIRST = 0x1200; // Header 消息
const Int32 HDM_SETIMAGELIST = HDM_FIRST + 8;
const Int32 HDM_GETIMAGELIST = HDM_FIRST + 9;
const Int32 HDM_GETITEM = HDM_FIRST + 11;
const Int32 HDM_SETITEM = HDM_FIRST + 12;
#endregion WIndows32 API...
//显示Header的图标
private void ShowHeaderIcon(ListView list, int columnIndex, SortOrder sortOrder)
{
if(columnIndex < 0 || columnIndex >= list.Columns.Count)
return;
IntPtr hHeader = SendMessage(list.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);
ColumnHeader colHdr = list.Columns[columnIndex];
HDITEM hd = new HDITEM();
hd.mask = HDI_IMAGE | HDI_FORMAT;
HorizontalAlignment align = colHdr.TextAlign;
if(align == HorizontalAlignment.Left)
hd.fmt = HDF_LEFT | HDF_STRING | HDF_BITMAP_ON_RIGHT;
else if(align == HorizontalAlignment.Center)
hd.fmt = HDF_CENTER | HDF_STRING | HDF_BITMAP_ON_RIGHT;
else // HorizontalAlignment.Right
hd.fmt = HDF_RIGHT | HDF_STRING;
if(sortOrder != SortOrder.None)
hd.fmt |= HDF_IMAGE;
hd.iImage = (int) sortOrder - 1;
SendMessage2(hHeader, HDM_SETITEM, new IntPtr(columnIndex), ref hd);
}
private void SetHeaderImageList(ListView list, ImageList imgList)
{
IntPtr hHeader = SendMessage(list.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);
SendMessage(hHeader, HDM_SETIMAGELIST, IntPtr.Zero, imgList.Handle);
}
#endregion Graphics
}
#endregion ListViewSortManager ...
}