简化了程序的逻辑,最大程度让大家明白我的意思!
程序功能:
每一行是一个button,当点击button后,通过 ThreadPool.QueueUserWorkItem,AutoResetEvent 去调用SetMessage 方法。
SetMessage方法返回当前的时间!
然后更新所在行的button的text 为 当前时间
程序效果图:
点击每一行的button后就等待更新 button的text
问题:
毫秒级别的更新会让 datagridview 卡卡的,我实际的程序就要求毫秒级别的更新。
可能你会说,改成5秒一更新就会不卡了,这样我也知道,可是程序需要的就是毫秒级别更新!!
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 common; using System.Threading; namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e) { //获取 button 行列号 int selectColumn = this.dataGridView1.CurrentCell.ColumnIndex; //lie int selectRow = this.dataGridView1.CurrentCell.RowIndex; MyAsync a = new MyAsync(); a.i = selectColumn; a.j = selectRow; AutoResetEvent asyncOPIsDone = a.asyncOPIsDone; ThreadPool.QueueUserWorkItem(new WaitCallback(myAsync), a); } public void myAsync(object state) { int col = ((MyAsync)state).i; int row = ((MyAsync)state).j; //循环更新 button 的text while (true) { ((MyAsync)state).SetMessage("now:"); dataGridView1[col, row].Value = ((MyAsync)state).message; } ((MyAsync)state).asyncOPIsDone.Set(); } /// <summary> /// datagridvie增加一行。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void addRow_Click(object sender, EventArgs e) { Button btn=new Button(); this.dataGridView1.Rows.Add(btn); } } }
public class MyAsync { public AutoResetEvent asyncOPIsDone = new AutoResetEvent(false); public string message; public int i; //column number public int j; //row number public void SetMessage(string strState) { message = strState + DateTime.Now.ToString("HH:mm:ss.fff"); } }
目前这样的毫秒级更新,当行多了,就会感觉卡!
更新:
总结了下大家的方法,多数都在说 控件重绘太耗资源了。
要自己去绘制! 自己绘制参考哪些知识呢?
自己绘制~
控件重绘太耗资源。
关注~
你用死循环去不停刷新,不卡才怪。你用个timer,每毫秒更新一次,不就行了。
毫秒你可以试试,用timer一样的卡!
找到问题所在了,是界面重绘卡。
与你说的timer完全无关
@水墨.MR.H: 你花2分钟自己跑个例子试试,新建一个winform程序,拖3个button(button1到button3),再拖一个timer,把timer的Interval属性设置成1,然后在timer的Tick事件里:
private void timer1_Tick(object sender, EventArgs e) { button1.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"); button2.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"); button3.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"); }
我刚试过了,毫无压力。
@水墨.MR.H: 我又试了下拖了10个button,毫无卡的迹象。如果你的程序卡,那一定是别的地方出了问题。
@水牛刀刀: 谢谢! 找到主要问题了,while(ture) 这个太耗资源了。
加上 Thread.sleep(1) 就好多了。
public void SetMessage(string strState)
{
message = strState + DateTime.Now.ToString("HH:mm:ss.fff");
Thread.sleep(1);
}
虽然看起来和timer 的 1毫秒 差不多,但是 消耗CPU资源远远小于 timer
因为timer 都是主线程在运算当前时间,而threadpool 只是重新赋值时候用到了主线程及UI线程。
不过,很谢谢你!
@水墨.MR.H: Thread.Sleep(1)暂停了1毫秒,实际算上上面程序执行的时间(非常短,小于1毫秒),那么你的button上的时间不是1毫秒刷新一次,而是1.xxxx毫秒刷新一次。不过估计也能接受了。
@水牛刀刀: 是的!
不过从CPU占用率来说, timer 太弱了,依靠主线程去计算。
还是委托其他线程计算,主线程只用来更新控件吧
1.按毫秒级别来更新的时候,你为什么要显示那么多行? 你都精确到毫秒级别了,人的眼睛能同时看几行? 大部分记录都可以记录下来,等人去查看。只有实时给人看的拿一小部分才需要刷到UI上去。
2.自己绘制控件请参考GDI+有关的内容。自己用GDI+绘制控件确实可以解决性能问题,但是如果你以前没做过,短时间内是不会解决你的性能问题的。先不考虑性能,一周之内自己能把控件丑陋地绘制出来就很不错了。
大量数据或者显示要求及时的地方你可以使用下面的思路:
1、数据源和数据视图要分离
2、假定你的表格控件最多能显示40行,那么你可以通过只显示40行进行刷新。
3、假如你的数据超过40行,那么只绑定40行的视图。(因为你要及时,毫秒级的,人眼是看不过来的。人如果想看详细的,弄个其他的表格看)
系统的listview支持大容量显示也需要实现手动管理数据显示,貌似是 OnScrollUp OnScrollDown等几个事件处理进行重绘要显示的那些行。