☰
使用C#编写任务管理器
2026/10/26 10:13:55 网站建设 项目流程

上手C# WinForms:手把手教你写一个Windows任务管理器

兔子个人的学习笔记,希望对你有帮助。


一、准备工作:环境与项目创建

1. 开发环境

  • Visual Studio 2019/2022(社区版免费即可)
  • 安装「.NET桌面开发」工作负载
  • 目标框架:.NET Framework 4.7.2 及以上(新手最稳的版本)

2. 创建项目

  1. 打开VS → 新建项目 → 选择「Windows 窗体应用(.NET Framework)」
  2. 项目名称命名为任意你喜欢的,这里兔子喜欢用日期+名称作为文件夹名选择保存路径,D盘啦,E盘啦看你哪个方便,或者直接放在VS的安装文件夹下。
  3. 点击创建,自动生成一个空白窗体Form1


二、界面搭建:拖拽控件即可完成的布局

我们不用写一行布局代码,全靠拖拽+属性设置就能完成专业的界面。先看最终用到的控件清单:

控件类型控件名称(Name)作用关键属性设置
ListViewlistViewProcess显示进程列表View=Details;FullRowSelect=True;HideSelection=False
ButtonbtnRefresh手动刷新Text=刷新进程
ButtonbtnKill结束进程Text=结束进程
TextBoxtxtSearch搜索输入清空默认Text
ButtonbtnSearch查询按钮Text=查询进程
ComboBoxcboAppPath启动程序选择DropDownStyle=DropDown;Items预设notepad.exe、calc.exe
ButtonbtnStartApp启动按钮Text=启动应用程序
LabellblCount显示进程数量Text=进程总数:0
TimertimerRefresh自动刷新Interval=2000;Enabled=True

布局步骤(自己觉得怎么好看怎么来)

接下来我们打开工具箱,一般在左侧,如果没有可以在视图里找,或者Ctrl+w,在点x

  1. 上方横向排列:刷新按钮(Button)、结束按钮(Button)、搜索输入框(TextBox)、查询按钮(Button)、程序下拉框(ComboBox)、启动按钮(Button),接下来在工具箱拖动或双击这些控件。[有四个按钮,可以拖一个,剩下直接选择复制]

选中任意控件,右击或按F4进入属性,找到Text可改变显示文字

2.中间大区域放listViewProcess,占满窗体下方

  1. 选中ListView → 右键「编辑列」,添加三列:PID(80px)、进程名称(160px)、内存占用(120px)
  2. 选中ListView → 属性里找到Anchor,设置为Top, Left, Right, Bottom,窗体会自动缩放

有人会,兔子兔子,我添加了列,为什么界面还是空白
答:ListView默认是大图标显示模式,只有Details模式才会显示列标题和列分布

最后一个Label同理,选中这个标签,按F4打开属性窗口,修改属性:

  • Name:改成lblCount(代码里用这个名字更新文字)
  • Text:改成进程总数:0(程序启动前的初始文字)
  • AutoSize:设为True(文字长度变化时自动调整宽度,不会被截断

补充:Timer是组件,拖入窗体后不会显示在界面上,会出现在设计界面底部的灰色组件里

💡 新手提示:所有事件方法都通过「双击控件」自动生成,不要手写方法名,能避免90%的绑定错误。


三、核心功能:从0到1实现进程管理

3.1 先引入必要的命名空间

打开Form1.cs,在顶部using区域添加一行,所有进程操作都在这个命名空间里:

using System.Diagnostics;

3.2 加载系统进程列表

这是最核心的基础方法,后续所有刷新、查询都会复用它。原理是调用系统APIProcess.GetProcesses()获取所有进程,再逐条添加到ListView。

private void LoadAllProcess() { listViewProcess.BeginUpdate(); // 暂停绘制,防闪烁 //记得把listView构件name改成listViewProcess,不然会报错 // 记录刷新前的选中项和滚动位置 int? selectedPid = null; int? topPid = null; //int?:可空整数类型 if (listViewProcess.SelectedItems.Count > 0) selectedPid = int.Parse(listViewProcess.SelectedItems[0].Text); if (listViewProcess.TopItem != null) topPid = int.Parse(listViewProcess.TopItem.Text); listViewProcess.Items.Clear(); Process[] allProcess = Process.GetProcesses(); lblCount.Text = $"进程总数:{allProcess.Length}"; foreach (Process p in allProcess) { try { ListViewItem item = new ListViewItem(p.Id.ToString()); item.SubItems.Add(p.ProcessName); item.SubItems.Add((p.WorkingSet64 / 1024.0 / 1024.0).ToString("0.00")); listViewProcess.Items.Add(item); } catch { /* 跳过权限不足的系统进程 */ } } // 恢复选中状态和滚动位置 if (selectedPid.HasValue) { foreach (ListViewItem item in listViewProcess.Items) { if (item.Text == selectedPid.Value.ToString()) { item.Selected = true; break; } } } if (topPid.HasValue) { foreach (ListViewItem item in listViewProcess.Items) { if (item.Text == topPid.Value.ToString()) { listViewProcess.TopItem = item; break; } } } listViewProcess.EndUpdate(); // 一次性重绘 }

窗体启动时自动调用:双击窗体空白处生成Form1_Load事件,写入:

private void Form1_Load(object sender, EventArgs e) { LoadAllProcess(); }

3.3 按名称查询进程

支持模糊查询、不区分大小写,输入为空时显示全部进程。

// 类成员变量:记录查询状态 private bool isSearchMode = false; private string currentKeyword = ""; private void btnSearch_Click(object sender, EventArgs e) { string keyword = txtSearch.Text.Trim(); currentKeyword = keyword; isSearchMode = keyword.Length > 0; listViewProcess.BeginUpdate(); // 保存刷新前的状态 int? selectedPid = null; int? topPid = null; if (listViewProcess.SelectedItems.Count > 0) selectedPid = int.Parse(listViewProcess.SelectedItems[0].Text); if (listViewProcess.TopItem != null) topPid = int.Parse(listViewProcess.TopItem.Text); listViewProcess.Items.Clear(); Process[] allProcess = Process.GetProcesses(); int matchCount = 0; foreach (Process p in allProcess) { try { // 关键词为空 或 进程名包含关键词(不区分大小写) if (keyword.Length == 0 || p.ProcessName.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) >= 0) { ListViewItem item = new ListViewItem(p.Id.ToString()); item.SubItems.Add(p.ProcessName); item.SubItems.Add((p.WorkingSet64 / 1024.0 / 1024.0).ToString("0.00")); listViewProcess.Items.Add(item); matchCount++; } } catch { } } lblCount.Text = $"匹配:{matchCount} / 总数:{allProcess.Length}"; // 恢复状态 if (selectedPid.HasValue) { foreach (ListViewItem item in listViewProcess.Items) { if (item.Text == selectedPid.Value.ToString()) { item.Selected = true; break; } } } if (topPid.HasValue) { foreach (ListViewItem item in listViewProcess.Items) { if (item.Text == topPid.Value.ToString()) { listViewProcess.TopItem = item; break; } } } listViewProcess.EndUpdate(); }

3.4 结束指定进程

通过PID精准定位进程,调用Kill()方法强制结束,加异常捕获避免权限不足崩溃。

private void btnKill_Click(object sender, EventArgs e) { if (listViewProcess.SelectedItems.Count == 0) { MessageBox.Show("请先选中一个进程!"); return; } // 直接取第一列文本就是PID string pidStr = listViewProcess.SelectedItems[0].Text; int pid = int.Parse(pidStr); try { Process target = Process.GetProcessById(pid); target.Kill(); MessageBox.Show("进程已结束!"); LoadAllProcess(); } catch (Exception ex) { MessageBox.Show("无法结束进程:" + ex.Message); } }

⚠️ 测试建议:用记事本(notepad)、计算器(calc)测试,不要随意结束系统核心进程。

3.5 启动新应用程序

同一个Process类不仅能结束进程,还能启动程序,支持程序名、完整路径、甚至网址。

private void btnStartApp_Click(object sender, EventArgs e) { string appName = cboAppPath.Text.Trim(); if (string.IsNullOrEmpty(appName) || appName == "请选择你需要打开的应用程序") { MessageBox.Show("请选择或输入要启动的程序!"); return; } try { Process.Start(appName); } catch (Exception ex) { MessageBox.Show("启动失败:" + ex.Message); } }

四、进阶体验:让任务管理器更好用

4.1 自动定时刷新

双击设计界面底部的timerRefresh组件,写入定时刷新逻辑,自动判断当前模式:

private void timerRefresh_Tick(object sender, EventArgs e) { if (isSearchMode) { // 查询模式下保持筛选 btnSearch_Click(sender, e); } else { // 普通模式刷新全部 LoadAllProcess(); } }

4.2 双缓冲彻底解决闪烁

ListView默认双缓冲是关闭的,用反射强制开启,刷新会平滑很多。在窗体构造函数里添加:

public Form1() { InitializeComponent(); // 开启ListView双缓冲 typeof(ListView).InvokeMember("DoubleBuffered", System.Reflection.BindingFlags.SetProperty | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic, null, listViewProcess, new object[] { true }); }

五、新手常见坑与解决方案

1. 报错 CS0111:已定义同名方法

原因:手动写了事件方法,又双击控件生成了一遍,导致重复定义。解决:删掉重复的方法,所有事件都通过「双击设计界面控件」自动生成。

2. 点击按钮没反应

原因:按钮的Click事件没绑定到对应的方法。解决:选中按钮 → 属性窗口点⚡闪电图标 → 找到Click行 → 下拉选择对应方法。

3. 刷新后选中行不见了

原因:清空+重建所有项,选中状态自然丢失。解决:刷新前记录PID,刷新完重新定位选中,本文代码已内置该逻辑。

4. 列表刷新一闪一闪

原因:每添加一行就重绘一次,几十次连续重绘造成闪烁。解决:用BeginUpdate+EndUpdate批量更新,配合双缓冲。

5. CS0103报错

原因:界面没有加上对应控件,或对应控件name属性没有修改


六、总结与扩展

你已经学到的

  • WinForms常用控件的布局与属性设置
  • System.Diagnostics.Process类的核心用法:获取、启动、结束进程
  • 事件驱动编程的基本思想
  • 界面性能优化的通用思路:批量更新、双缓冲、状态保持

可以继续扩展的功能

  1. 右键菜单:添加「打开文件位置」「结束进程树」
  2. 实时显示CPU、内存使用率
  3. 进程排序:点击列标题按PID/名称/内存排序
  4. 最小化到系统托盘
  5. 自定义皮肤与背景图

整个项目写下来不到300行代码,但涵盖了WinForms开发最核心的流程:界面设计→事件绑定→逻辑编写→性能优化。非常适合作为C#桌面开发的入门练手项目,做完之后再去做其他WinForms程序都会得心应手。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询