我是C#和.NET编程的新手,我正在尝试开发一个类似Windows的Windows窗体应用程序。 我首先使用从System.Diagnostics.Process收集的信息填充listView,然后使用MethodInvoker委托启动System.Threading.Timer,该委托尝试每秒刷新listview数据。
问题是应用程序 真的 缓慢,而且,当然,我正在做一些无用的事情。
public partial class Form1 : Form
{
private System.Threading.Timer t;
private Process[] procVett;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.loadAppInfo(null);
TimerCallback timerDelegate = new TimerCallback(this.refresh);
this.t = new System.Threading.Timer(timerDelegate, null, 1000, 3000);
}
private void refresh(Object stateInfo)
{
procVett = Process.GetProcesses();
this.BeginInvoke( (MethodInvoker)delegate
{
ListView.ListViewItemCollection ic = this.appList.Items;
ListView.ListViewItemCollection procIc = this.procList.Items;
time.Text = DateTime.Now.ToLongTimeString();
int count = 0;
procList.BeginUpdate();
foreach (Process p in procVett)
{
try
{
string cputime = p.TotalProcessorTime.TotalMinutes.ToString();
procIc[count].SubItems[1].Text = ("");
procIc[count].SubItems[2].Text = (cputime);
procIc[count].SubItems[3].Text =(p.WorkingSet64.ToString());
procIc[count].SubItems[4].Text = ("");
}
catch (System.Exception)
{
}
count++;
}
procList.EndUpdate();
}, null);
}
}
答案 0 :(得分:2)
你基本上是在正确的轨道上,但是在你循环遍历数组中的进程以收集TotalProcessorTime时间值之前,我会避免调用BeginInvoke方法。
基本上,经验法则是尽可能少花时间在UI线程上 - 尽可能多地使用后台进程。
此外,请确保您没有在线程池中堆积线程或调度。从Timer类的MSDN文档:
如果SynchronizingObject属性为null 引用(在Visual Basic中没有任何内容),Elapsed事件在a上引发 ThreadPool线程。如果处理Elapsed事件持续时间更长 比Interval,可能会在另一个ThreadPool上再次引发该事件 线。在这种情况下,事件处理程序应该是可重入的。
因此,请注意重入,并忽略重入计时器事件,或者终止旧线程上的处理(使用一些线程安全信令机制)。
答案 1 :(得分:1)
除了我在评论中所说的内容:
我想创建一个ListViewItems的独立集合,将进程信息解析为另一个线程(BackgroundWorker或简单的另一个线程),并在完成更新后在ListView中使用该集合,这样就可以了当前显示的列表不会被冻结。
答案 2 :(得分:0)
我建议在ListView上使用VirtualMode,它只显示当前视图中的项目。如果您有1,000,000个项目,并且它只绘制#1,000-1020,那么它会请求它们,您告诉它如何从内存中的项目列表中获取它们,并绘制它们。
它比自己添加ListViewItems要快得多,这非常慢。
以下是它的入门教程:Virtual Mode ListView
另外,我今天早上刚开始使用ObjectListView,这太棒了。