一直想写一个带进度条的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();
}
}
}
以上就是 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();
}
}
}
构造函数里面 是对 ProgressListview 的初始化 ,本例中我通过点击按钮 button1 来实现了一个进度条的更新,当点击 button1 按钮时,进度条会更新,且会显示百分比进度。
附加如下截图 ,界面可能不是很好看,哈哈。