在这篇文章中,我们将介绍如何使用 C# 和 Windows Forms 创建一个简单的文件下载器。这个程序将读取一个包含下载链接的文件,并显示每个文件的下载进度。
前置条件
在开始之前,确保你已经安装了以下开发工具:
- Visual Studio
- .NET Framework
步骤 1:创建 Windows Forms 应用程序
首先,我们需要创建一个新的 Windows Forms 应用程序。打开 Visual Studio,选择 "新建项目",然后选择 "Windows Forms 应用程序" 模板。
步骤 2:设计用户界面
在设计器中,我们需要添加以下控件:
- 一个
Button
控件用于开始下载操作,命名为btnTest
。 - 一个
ListView
控件用于显示下载进度,命名为listView1
。
配置 ListView
控件的列来显示下载项的信息,例如文件名、下载进度、速度等。
步骤 3:实现代码逻辑
接下来,我们需要编写代码来处理文件下载和进度更新。
以下是完整的代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;
using Gac;
namespace Demo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
DownLoadFile dlf = new DownLoadFile();
private void btnTest_Click(object sender, EventArgs e)
{
string[] lines = File.ReadAllLines("软件下载1.txt");
for (int i = 0; i < lines.Length; i++)
{
string[] line = lines[i].Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
if (line.Length == 2)
{
string path = Uri.EscapeUriString(line[1]);
string filename = Path.GetFileName(path);
string dir = @"F:\test";
ListViewItem item = listView1.Items.Add(new ListViewItem(new string[] { (listView1.Items.Count + 1).ToString(), filename, "0", "0", "0%", "0", "0", DateTime.Now.ToString(), "等待中", line[1] }));
int id = item.Index;
dlf.AddDown(path, dir, id, id.ToString());
}
}
dlf.StartDown();
}
private void Form1_Load(object sender, EventArgs e)
{
dlf.ThreadNum = 3; // 线程数,不设置默认为3
dlf.doSendMsg += SendMsgHander; // 下载过程处理事件
}
private void SendMsgHander(DownMsg msg)
{
switch (msg.Tag)
{
case DownStatus.Start:
this.Invoke((MethodInvoker)delegate ()
{
listView1.Items[msg.Id].SubItems[8].Text = "开始下载";
listView1.Items[msg.Id].SubItems[7].Text = DateTime.Now.ToString();
});
break;
case DownStatus.GetLength:
this.Invoke((MethodInvoker)delegate ()
{
listView1.Items[msg.Id].SubItems[3].Text = msg.LengthInfo;
listView1.Items[msg.Id].SubItems[8].Text = "连接成功";
});
break;
case DownStatus.End:
case DownStatus.DownLoad:
this.Invoke(new MethodInvoker(() =>
{
this.Invoke((MethodInvoker)delegate ()
{
listView1.Items[msg.Id].SubItems[2].Text = msg.SizeInfo;
listView1.Items[msg.Id].SubItems[4].Text = msg.Progress.ToString() + "%";
listView1.Items[msg.Id].SubItems[5].Text = msg.SpeedInfo;
listView1.Items[msg.Id].SubItems[6].Text = msg.SurplusInfo;
if (msg.Tag == DownStatus.DownLoad)
{
listView1.Items[msg.Id].SubItems[8].Text = "下载中";
}
else
{
listView1.Items[msg.Id].SubItems[8].Text = "下载完成";
}
Application.DoEvents();
});
}));
break;
case DownStatus.Error:
this.Invoke((MethodInvoker)delegate ()
{
listView1.Items[msg.Id].SubItems[6].Text = "失败";
listView1.Items[msg.Id].SubItems[8].Text = msg.ErrMessage;
Application.DoEvents();
});
break;
}
}
}
}
代码逐句分析
-
命名空间和类定义
namespace Demo { public partial class Form1 : Form { public Form1() { InitializeComponent(); } // ... } }
我们创建了一个命名空间
Demo
并定义了一个Form1
类,这个类继承自Form
类。 -
定义下载对象
DownLoadFile dlf = new DownLoadFile();
在
Form1
类中创建一个DownLoadFile
对象dlf
,它将用于处理文件下载操作。 -
按钮点击事件
private void btnTest_Click(object sender, EventArgs e) { // ... }
这是按钮 (
btnTest
) 的点击事件处理方法,它将触发下载操作。 -
读取下载链接并启动下载
string[] lines = File.ReadAllLines("软件下载1.txt"); for (int i = 0; i < lines.Length; i++) { string[] line = lines[i].Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries); if (line.Length == 2) { string path = Uri.EscapeUriString(line[1]); string filename = Path.GetFileName(path); string dir = @"F:\test"; ListViewItem item = listView1.Items.Add(new ListViewItem(new string[] { (listView1.Items.Count + 1).ToString(), filename, "0", "0", "0%", "0", "0", DateTime.Now.ToString(), "等待中", line[1] })); int id = item.Index; dlf.AddDown(path, dir, id, id.ToString()); } } dlf.StartDown();
从文件 "软件下载1.txt" 中读取所有行。对每一行进行处理,解析出文件路径。在
ListView
中添加一项以显示下载信息。调用dlf.AddDown
方法添加下载任务,并启动下载。 -
窗体加载事件
private void Form1_Load(object sender, EventArgs e) { dlf.ThreadNum = 3; // 线程数,不设置默认为3 dlf.doSendMsg += SendMsgHander; // 下载过程处理事件 }
在窗体加载时设置下载线程数(默认为3)。
将SendMsgHander
方法附加到doSendMsg
事件,用于处理下载过程中的消息。 -
下载消息处理
private void SendMsgHander(DownMsg msg) { switch (msg.Tag) { case DownStatus.Start: this.Invoke((MethodInvoker)delegate () { listView1.Items[msg.Id].SubItems[8].Text = "开始下载"; listView1.Items[msg.Id].SubItems[7].Text = DateTime.Now.ToString(); }); break; case DownStatus.GetLength: this.Invoke((MethodInvoker)delegate () { listView1.Items[msg.Id].SubItems[3].Text = msg.LengthInfo; listView1.Items[msg.Id].SubItems[8].Text = "连接成功"; }); break; case DownStatus.End: case DownStatus.DownLoad: this.Invoke(new MethodInvoker(() => { this.Invoke((MethodInvoker)delegate () { listView1.Items[msg.Id].SubItems[2].Text = msg.SizeInfo; listView1.Items[msg.Id].SubItems[4].Text = msg.Progress.ToString() + "%"; listView1.Items[msg.Id].SubItems[5].Text = msg.SpeedInfo; listView1.Items[msg.Id].SubItems[6].Text = msg.SurplusInfo; if (msg.Tag == DownStatus.DownLoad) { listView1.Items[msg.Id].SubItems[8].Text = "下载中"; } else { listView1.Items[msg.Id].SubItems[8].Text = "下载完成"; } Application.DoEvents(); }); })); break; case DownStatus.Error: this.Invoke((MethodInvoker)delegate () { listView1.Items[msg.Id].SubItems[6].Text = "失败"; listView1.Items[msg.Id].SubItems[8].Text = msg.ErrMessage; Application.DoEvents(); }); break; } }
根据
DownMsg
的Tag
属性处理不同的下载状态。使用Invoke
方法确保跨线程调用更新 UI 控件。总结
通过上述步骤,我们创建了一个简单的文件下载器。这个应用程序可以读取下载链接文件,并显示每个文件的下载进度和状态。