刷新列表视图会使程序变得非常慢

时间:2012-06-21 17:55:36

标签: c# winforms multithreading listview

我是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);

        }
}

3 个答案:

答案 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,这太棒了。