using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Windows.Forms; using WinApi; namespace DPumpHydr.WinFrmUI.WenSkin.Controls { [ToolboxBitmap(typeof(ListView))] public partial class WenListView : ListView { public WenListView() { this.View = View.Details; this.FullRowSelect = true; base.SetStyle( //ControlStyles.UserPaint | ControlStyles.DoubleBuffer | ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor, true); base.UpdateStyles(); OwnerDraw = true; this.BackColor = Color.FromArgb(37, 37, 38); this.BorderStyle = BorderStyle.FixedSingle; itemlistInstance(); this.ForeColor = Color.White; } #region 私有属性 private int itemHeight = 30; private Size itemIconSize = new Size(30, 30); private WenListViewColumnHeaderCollection columns; private WenListViewItemCollection items; #endregion #region 公有属性 [Category("Wen"), Description("当imagelist无值 默认图标"), DefaultValue(null)] public Image ItemIcon { get; set; } [Category("Wen"), Description("没有图标情况,项高度"), DefaultValue(30)] public int ItemHeight { get => itemHeight; set { itemHeight = value; itemIconSize = new Size(value, value); itemlistInstance(); this.Invalidate(); } } public Color HeadColor { get; set; } #endregion #region 重写属性 [Category("Wen"), Description("是否显示复选框"), DefaultValue(false)] public new bool CheckBoxes { get => base.CheckBoxes; set => base.CheckBoxes = value; } public new ImageList SmallImageList { get; set; } [Category("Wen"), Description("项集合")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public new WenListViewItemCollection Items => items ?? (items = new WenListViewItemCollection(this)); [Category("Wen"), Description("列集合")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] [Editor(typeof(Design.Editor.WenCollectionEditor), typeof(System.Drawing.Design.UITypeEditor))] public new WenListViewColumnHeaderCollection Columns => columns ?? (columns = new WenListViewColumnHeaderCollection(this)); #endregion #region 委托 public delegate void WenListViewItemEventHandler(object sender, WenListViewItemEventArgs e); public class WenListViewItemEventArgs: EventArgs { public WenListViewItemEventArgs(WenListViewItem wenListViewItem) { WenListViewItem = wenListViewItem; } public WenListViewItem WenListViewItem { get; set; } } [Category("Wen"), Description("Item 项鼠标点击事件")] public event WenListViewItemEventHandler WenListViewItemClick; #endregion #region 绑定数据 private object dataSource { get; set; } [Browsable(false)] public object DataSource { get => dataSource; set { if (value != null) { dataSource = value; DataBind(); } } } private void DataBind() { if (dataSource == null) return; this.Items.Clear(); switch (dataSource) { case DataSet ds: DataBind(ds.Tables[0]); break; case DataTable dt: DataBind(dt); break; case IList ilist: { foreach (var li in ilist) { WenListViewItem item = new WenListViewItem(this) { Tag = ilist, ImageIndex = 0 }; foreach (WenColumnHeader cl in Columns) { List propertyInfos = new List(li.GetType().GetProperties()); string value = propertyInfos .Find(a => a.Name.ToUpper() == cl.CloumnName.ToUpper())?.GetValue(li, null)?.ToString(); item.Cells.Add(cl.CloumnName, value); if (Columns.IndexOf(cl) == 0) item.Text = value; else item.SubItems.Add(value); } Items.Add(item); } break; } } //绑定DataTable 数据 void DataBind(DataTable dt) { foreach (DataRow dr in dt.Rows) { WenListViewItem item = new WenListViewItem(this) { Tag = dr, ImageIndex = 0 }; foreach (WenColumnHeader cl in Columns) { string value = dr[cl.CloumnName]?.ToString(); item.Cells.Add(cl.CloumnName,value); if (Columns.IndexOf(cl) == 0) item.Text = value; else item.SubItems.Add(value); } Items.Add(item); } } } private ImageList itemlistInstance() { ImageList imageList = new ImageList() { ImageSize = itemIconSize }; if (ItemIcon != null) imageList.Images.Add(ItemIcon); else imageList.Images.Add(Properties.Resources.itemImage); base.SmallImageList = imageList; return imageList; } #endregion #region 重绘项目 protected override void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e) { Graphics g = e.Graphics; g.SetGDIHigh(); Rectangle rec = e.Bounds; using Brush b = new SolidBrush(Color.FromArgb(45, 45, 48)); using Brush bstr = new SolidBrush(Color.FromArgb(199, 199, 199)); using Pen p = new Pen(Color.FromArgb(199, 199, 199)); //画背景 g.FillRectangle(b, new Rectangle(rec.X , rec.Y, rec.Width, rec.Height - 1)); //画分割线 g.DrawLine(p, rec.X + rec.Width-1, rec.Y, rec.X + rec.Width-1, rec.Y + rec.Height); //画文字 g.DrawString(e.Header.Text, this.Font, bstr, rec, ControlHelper.StringConters); } protected override void OnDrawItem(DrawListViewItemEventArgs e) { Graphics g = e.Graphics; g.ResetClip(); g.SetGDIHigh(); Rectangle rec = new Rectangle(0, e.Bounds.Y, this.Width, e.Bounds.Height); using Pen pen = new Pen(Color.FromArgb(70, 70, 70)); g.DrawLine(pen, 0, rec.Y + rec.Height - 1, rec.Width, rec.Y + rec.Height - 1); } protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e) { if (e.Item.ImageIndex < 0) { e.Item.ImageIndex = 0; } Graphics g = e.Graphics; g.SetGDIHigh(); Rectangle rec = new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width+1, e.Bounds.Height); Rectangle recStr = rec; g.SetClip(new Rectangle(rec.X, rec.Y+1, rec.Width, rec.Height - 3)); //当为最后一列数据时事件 if (e.ColumnIndex + 1 == this.Columns.Count) { g.SetClip(new Rectangle(rec.X, rec.Y + 1, rec.Width - 1, rec.Height - 3)); } using Brush bSelected = new SolidBrush(Color.FromArgb(63, 63, 70)); using Brush bNone = new SolidBrush(Color.FromArgb(37,37,38)); DrawBackdrop(g, rec); //画背景 void DrawBackdrop(Graphics g,Rectangle rec) { if (e.Item.Selected) g.FillRectangle(bSelected, rec);//选中 else g.FillRectangle(bNone, rec);//普通 } //判定为第一列,画图标 using Brush brush = new SolidBrush(this.ForeColor); Image image = e.Item.ImageList.Images[e.Item.ImageIndex]; //获取文字宽度 if (e.ColumnIndex == 0) { var numFormat = "d" + this.Items.Count.ToString().Length; int indexWidth = TextRenderer.MeasureText((e.ItemIndex + 1).ToString(numFormat), e.Item.Font).Width + 2; Rectangle recItemLine = new Rectangle(rec.X, rec.Y, indexWidth, rec.Height); Rectangle recImage = new Rectangle(rec.X + indexWidth + 3, rec.Y + (rec.Height - image.Height / 2) / 2, image.Width / 2, image.Height / 2); //重置绘制文字区域 recStr = new Rectangle(recImage.X + recImage.Width + 3, rec.Y, rec.Width - recItemLine.Width - recImage.Width, rec.Height); if (this.CheckBoxes) { int checkWidth = 15; recItemLine.Offset(checkWidth, 0); recImage.Offset(checkWidth, 0); recStr.Offset(checkWidth, 0); int checkY = (rec.Height - checkWidth) / 2 + rec.Y; if (e.Item.Checked) { CheckBoxRenderer.DrawCheckBox(g, new Point(rec.X, checkY), System.Windows.Forms.VisualStyles.CheckBoxState.CheckedNormal); } else { CheckBoxRenderer.DrawCheckBox(g, new Point(rec.X, checkY), System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal); } } g.DrawImage(image, recImage); g.DrawString((e.ItemIndex + 1).ToString(numFormat), e.Item.Font, brush, recItemLine, ControlHelper.StringConters); } g.DrawString(e.SubItem.Text, e.Item.Font, brush, recStr, ControlHelper.StringConters); } #endregion #region 项点击事件 protected override void OnMouseClick(MouseEventArgs e) { base.OnMouseClick(e); if(GetItemAt(e.X, e.Y) is WenListViewItem item) { WenListViewItemClick?.Invoke(this, new WenListViewItemEventArgs(item)); } } #endregion #region 空白区域美化 protected override void CreateHandle() { base.CreateHandle(); if (headerNativeWindow == null) { headerNativeWindow = new HeaderNativeWindow(this); } } protected override void DestroyHandle() { base.DestroyHandle(); if (headerNativeWindow != null) { headerNativeWindow = null; } } IntPtr headerWnd => WindowsAPI.FindWindowEx(this.Handle, IntPtr.Zero, "SysHeader32", null); private Rectangle HeaderEndRect() { RECT rect = new RECT(); RECT rect2 = new RECT(); WindowsAPI.SendMessage(headerWnd, 0x1207, Columns.Count - 1, ref rect); WindowsAPI.GetWindowRect(headerWnd, ref rect2); return new Rectangle(rect.X + rect.Width , rect.Y, this.Width - (rect.X + rect.Width), rect.Height); } HeaderNativeWindow headerNativeWindow; private class HeaderNativeWindow : NativeWindow { public WenListView owner; IntPtr header; public HeaderNativeWindow(WenListView owner) { this.owner = owner; header = owner.headerWnd; base.AssignHandle(header); } protected override void WndProc(ref Message m) { base.WndProc(ref m); if (m.Msg == 0xF || m.Msg == 0x47) { IntPtr hdc = WindowsAPI.GetDC(m.HWnd); try { using Graphics g = Graphics.FromHdc(hdc); Rectangle rec = owner.HeaderEndRect(); owner.ReHeader(g, rec); } finally { WindowsAPI.ReleaseDC(m.HWnd, hdc); } } } } private void ReHeader(Graphics g, Rectangle rec) { g.FillRectangle(new SolidBrush(Color.FromArgb(45, 45, 48)), rec); } #endregion public class WenListViewColumnHeaderCollection : ColumnHeaderCollection { private readonly WenListView owner; public WenListViewColumnHeaderCollection(WenListView owner) : base(owner) { this.owner = owner; } public new WenColumnHeader this[string key] { get { foreach (WenColumnHeader item in this) { if (item.Text.ToUpper() == key.ToUpper()) { return item; } } return null; } } public void Add(WenColumnHeader value) { base.Add(value); } public void AddRange(WenColumnHeader[] values) { base.AddRange(values); } } public class WenListViewItemCollection : ListViewItemCollection { public WenListViewItemCollection(WenListView owner) : base(owner) { } public new WenListViewItem this[int index] => (base[index] is WenListViewItem item) ? item : null; public void Add(WenListViewItem value) { base.Add(value); } } } }