一直想寫一個帶進度條的Listview組件,方便以後要用到,由於平時上班忙,沒什麼時間,下班時間又不想動,懶的寫。就利用上班時間不忙的時候花了點時間寫出來了。
注意:要重繪 Listview 子項,必須要將 Listview 的 OwnerDraw 屬性值設置為 True ,否則即使你的重寫將不會生效。
組件代碼:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Text; using System.Windows.Forms; using System.Drawing; namespace Control.Listview { partial class ProgressListview { /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// Clean up any resources being used. /// </summary> /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Component Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { components = new System.ComponentModel.Container(); } #endregion } public partial class ProgressListview : ListView { /// <summary> /// 進度條列索引 /// </summary> private int _progressColumnIndex = -1; public int ProgressColumnIndex { get { return _progressColumnIndex; } set { _progressColumnIndex = value; } } /// <summary> /// 進度條最大值 /// </summary> private int _progressMaximun = 100; public int ProgressMaximun { get { return _progressMaximun; } } public ProgressListview() { InitializeComponent(); } public ProgressListview(IContainer container) { container.Add(this); InitializeComponent(); } protected override void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e) { e.DrawDefault = true; base.OnDrawColumnHeader(e); } protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e) { if (e.ColumnIndex == ProgressColumnIndex) { var item = e.Item.SubItems[1]; var rect = item.Bounds; //繪制進度條 var g = e.Graphics; var progressRect = new Rectangle(rect.X + 1, rect.Y + 3, rect.Width - 2, rect.Height - 5); g.DrawRectangle(new Pen(new SolidBrush(Color.Blue), 1), progressRect); //繪制進度 var progressMaxWidth = progressRect.Width - 1; var unit = (progressMaxWidth * 1.0) / (_progressMaximun * 100); var fValue = float.Parse(item.Text); var percent = fValue * unit * 100; if (percent >= progressMaxWidth) percent = progressMaxWidth; g.FillRectangle(new SolidBrush(Color.Red), new RectangleF(progressRect.X + 1, progressRect.Y + 1, float.Parse(percent.ToString()), progressRect.Height - 1)); //繪制進度百分比 percent = fValue; var percentText = string.Format("{0}% ...", percent); if (fValue >= _progressMaximun) percentText = "已完成"; var size = TextRenderer.MeasureText(percentText.ToString(), Font); var x = rect.X + (progressRect.Width - size.Width) / 2.0; var y = rect.Y + (progressRect.Height - size.Height) / 2.0 + 3; g.DrawString(percentText, this.Font, new SolidBrush(Color.Black), float.Parse(x.ToString()), float.Parse(y.ToString())); } else { e.DrawDefault = true; } base.OnDrawSubItem(e); } public void SetProgress(int itemIndex, int value) { var columnWidth = this.Columns[ProgressColumnIndex].Width; var progressSubItem = this.Items[itemIndex].SubItems[ProgressColumnIndex]; progressSubItem.Text = value.ToString(); } } } using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Text; using System.Windows.Forms; using System.Drawing; namespace Control.Listview { partial class ProgressListview { /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// Clean up any resources being used. /// </summary> /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Component Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { components = new System.ComponentModel.Container(); } #endregion } public partial class ProgressListview : ListView { /// <summary> /// 進度條列索引 /// </summary> private int _progressColumnIndex = -1; public int ProgressColumnIndex { get { return _progressColumnIndex; } set { _progressColumnIndex = value; } } /// <summary> /// 進度條最大值 /// </summary> private int _progressMaximun = 100; public int ProgressMaximun { get { return _progressMaximun; } } public ProgressListview() { InitializeComponent(); } public ProgressListview(IContainer container) { container.Add(this); InitializeComponent(); } protected override void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e) { e.DrawDefault = true; base.OnDrawColumnHeader(e); } protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e) { if (e.ColumnIndex == ProgressColumnIndex) { var item = e.Item.SubItems[1]; var rect = item.Bounds; //繪制進度條 var g = e.Graphics; var progressRect = new Rectangle(rect.X + 1, rect.Y + 3, rect.Width - 2, rect.Height - 5); g.DrawRectangle(new Pen(new SolidBrush(Color.Blue), 1), progressRect); //繪制進度 var progressMaxWidth = progressRect.Width - 1; var unit = (progressMaxWidth * 1.0) / (_progressMaximun * 100); var fValue = float.Parse(item.Text); var percent = fValue * unit * 100; if (percent >= progressMaxWidth) percent = progressMaxWidth; g.FillRectangle(new SolidBrush(Color.Red), new RectangleF(progressRect.X + 1, progressRect.Y + 1, float.Parse(percent.ToString()), progressRect.Height - 1)); //繪制進度百分比 percent = fValue; var percentText = string.Format("{0}% ...", percent); if (fValue >= _progressMaximun) percentText = "已完成"; var size = TextRenderer.MeasureText(percentText.ToString(), Font); var x = rect.X + (progressRect.Width - size.Width) / 2.0; var y = rect.Y + (progressRect.Height - size.Height) / 2.0 + 3; g.DrawString(percentText, this.Font, new SolidBrush(Color.Black), float.Parse(x.ToString()), float.Parse(y.ToString())); } else { e.DrawDefault = true; } base.OnDrawSubItem(e); } public void SetProgress(int itemIndex, int value) { var columnWidth = this.Columns[ProgressColumnIndex].Width; var progressSubItem = this.Items[itemIndex].SubItems[ProgressColumnIndex]; progressSubItem.Text = value.ToString(); } } }
以上就是 ProgressListview 組件的全部代碼,對 Listview 的兩個方法進行了重寫,核心代碼在 OnDrawSubItem這個方法內,通過繪制一個帶邊框的矩形和一個實心的矩形就可以實現簡單的進度條效果了;對這個 OnDrawColumnHeader 函數的重寫,主要是將其 DrawDefault 設置為True ,因為當 Listview的 Ownerdraw 屬性設置為True時,OnDrawColumnHeader也會默認要求重繪,這裡我們不需要重繪列頭,所以將其 DrawDefault 設置為true。
通過ProgressColumnIndex 屬性來設置進度條列,還可以通過調用組件的SetProgress 函數動態設置進度條的進度,進度條的Maximun值內置為100;
以下是對該組件的調用代碼:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading; namespace Control.Listview { public partial class Form1 : Form { public Form1() { InitializeComponent(); CheckForIllegalCrossThreadCalls = false; uploadListview1.ProgressColumnIndex = 1; var percentArray = new int[] { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }; foreach (var percent in percentArray) { var listViewItem = new ListViewItem(); uploadListview1.Items.Add(listViewItem); listViewItem.SubItems.AddRange(new string[] { percent.ToString(), (percent + 1).ToString(), (percent + 2).ToString() }); } } private void button1_Click(object sender, EventArgs e) { var th = new Thread(delegate() { for (var i = 0; i < 101; i++) { uploadListview1.SetProgress(1, i); Thread.Sleep(100); } }); th.IsBackground = true; th.Start(); } } } using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading; namespace Control.Listview { public partial class Form1 : Form { public Form1() { InitializeComponent(); CheckForIllegalCrossThreadCalls = false; uploadListview1.ProgressColumnIndex = 1; var percentArray = new int[] { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }; foreach (var percent in percentArray) { var listViewItem = new ListViewItem(); uploadListview1.Items.Add(listViewItem); listViewItem.SubItems.AddRange(new string[] { percent.ToString(), (percent + 1).ToString(), (percent + 2).ToString() }); } } private void button1_Click(object sender, EventArgs e) { var th = new Thread(delegate() { for (var i = 0; i < 101; i++) { uploadListview1.SetProgress(1, i); Thread.Sleep(100); } }); th.IsBackground = true; th.Start(); } } }
構造函數裡面 是對 ProgressListview 的初始化 ,本例中我通過點擊按鈕 button1 來實現了一個進度條的更新,當點擊 button1 按鈕時,進度條會更新,且會顯示百分比進度。
附加如下截圖 ,界面可能不是很好看,哈哈。