首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > C# >

百分有关问题 C#一个困扰了好几天的有关问题,winform界面很多控件即时刷新时,界面很卡,已使用BeginInvoke

2013-12-23 
百分问题 C#一个困扰了好几天的问题,winform界面很多控件即时刷新时,界面很卡,已使用BeginInvoke目前做一

百分问题 C#一个困扰了好几天的问题,winform界面很多控件即时刷新时,界面很卡,已使用BeginInvoke
目前做一个即时监控软件,大数据量接收后,分门别类的传输到winform上的各个控件,显示
winform上大概有40多个控件,主要为 textbox,NI系列的AxCWSlide,AxCWKnob,AxCWGraph
接收端启用一个事件把数据传递到winform端,winform端按照规则分类后传递到各个控件,规则我是在控件的tag内置定的

现在的问题是,数据量大到一定层度时(远远未到要求值),winform界面开始卡,显示开始不正常
我怀疑是UI线程堵塞,处理不过来了,但是又找不到什么好的办法
我以前做C的,这是第一个C#项目,请各位C#大牛多多指点,兄弟先谢谢了

附上部分代码


/////////////
////////前面通过这个事件激活winform这边的处理函数ShowData()
        KindsFunction.SendDat += new KindsFunction.SendDatDelegate(ShowData);        
/////////////



        private delegate void ShowTextDelegate(double[] Dat);

        private void ShowData(object Dat)
        {
            {
                if (this.InvokeRequired)
                {
                    double[] data = null;
                    data = (double[])Dat;//传过来的数据

                    object[] obj ={ data };
                     
                    //异步调用委托
                    this.BeginInvoke(new ShowTextDelegate(ShowText), obj);
                }
                else
                {
                    //ShowText_short(data_short);
                    //ShowText_byte(data_byte);
                }
            }
        }

        string SubTag;
        string GraphType = "array";

        //界面上的控件处理
        private void ShowText(double[] Dat)
        {
            try
            {
                foreach (Control temp in this.Controls)///遍历整个控件
                {
                    if (temp is TextBox)
                    {
                        SubTag = temp.Tag.ToString().Substring(5);
                        if (Dat[0] == Convert.ToDouble(SubTag))////通过当前控件的tag值,与数据中的标示做比较
                        {
                            for (int i = 1; i < Dat.Length; i = i + 99)
                            {
                                temp.Text = Dat[i].ToString();//写入数据
                            }
                        }
                    }
                    else if (temp is AxCWUIControlsLib.AxCWSlide)


                    {
                        AxCWUIControlsLib.AxCWSlide Slide = (AxCWUIControlsLib.AxCWSlide)temp;
                        SubTag = Slide.Tag.ToString().Substring(5);
                        if (Dat[0] == Convert.ToDouble(SubTag))
                        {
                            for (int i = 1; i < Dat.Length; i++)
                            {
                                Slide.Value = Dat[i];
                            }
                        }
                    }
                    else if (temp is AxCWUIControlsLib.AxCWKnob)
                    {
                        AxCWUIControlsLib.AxCWKnob Knob = (AxCWUIControlsLib.AxCWKnob)temp;
                        SubTag = Knob.Tag.ToString().Substring(5);
                        if (Dat[0] == Convert.ToDouble(SubTag))
                        {
                            for (int i = 1; i < Dat.Length; i++)
                            {
                                Knob.Value = Dat[i];
                            }
                        }
                    }
                    else if (temp is AxCWUIControlsLib.AxCWGraph)
                    {
 
                    }
                }
            }
            catch { }
        }


[解决办法]
引用:
对了,忘了说, ShowData()函数每秒钟触发的次数需要达到至少 2000次/每秒 。。。。。



这么大的量啊
看得过来吗?
SubTag = temp.Tag.ToString().Substring(5);
不要用Tag
不要用Substring
最好能精确定位到要操作的控件
最好连控件都不要,DrawString

百分有关问题 C#一个困扰了好几天的有关问题,winform界面很多控件即时刷新时,界面很卡,已使用BeginInvoke

[解决办法]
你显示数据是给人看的,2000次,谁能反应过来呀?若是要求实时性,就检测当数据变化时,再重绘窗体。
[解决办法]
个人觉得你可以采取折中办法,后台处理数据继续2000/秒也可以(虽然觉得没必要)。。前台你只需要0.1秒或者多少刷新一次就可以了,看起来也完全是「实时」的。。

也就说在你数据处理中「完全处理,抽样显示」。。百分有关问题 C#一个困扰了好几天的有关问题,winform界面很多控件即时刷新时,界面很卡,已使用BeginInvoke
[解决办法]
                            for (int i = 1; i < Dat.Length; i = i + 99)
                            {
                                temp.Text = Dat[i].ToString();//写入数据
                            }
这样的代码很让人费解,你直接计算控件最终要写入的值,只写入一次不好吗?
用12楼的思路比较好,在ShowData里把数据保存到内存,然后用一个timer定期刷新界面就行了,要注意lock

SubTag = temp.Tag.ToString().Substring(5);
if (Dat[0] == Convert.ToDouble(SubTag))
这里也应该能优化的,可以建一个类,分别保存tag的前5个字符,和后面的double数据,再把这样的对象赋给控件的tag,可以节省不少时间
[解决办法]
看了楼主的代码
1.像这样大量数据操作时,影响到主线程了,必须开线程。
2.大量数据操作不要循环嵌套,一层循环都最好不要。----思路问题

建议
1.开线程处理数据。
2.在执行数据处理的时候关闭界面重绘。可用sendmessage API

        [DllImport("user32")]
        private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, IntPtr lParam);
        private const int WM_SETREDRAW = 0xB;

SendMessage(AddClientContrl.Handle, WM_SETREDRAW, 0, IntPtr.Zero);//禁止该控件重绘
SendMessage(AddClientContrl.Handle, WM_SETREDRAW, 1, IntPtr.Zero);//开启该控件重绘
3.数据绑定后再开启重绘 强制重绘一次
4.处理数据的时候。最好给该数据打好标记。避免循环。控件用tag属性可以存object
5.循环里面尽量少声明变量   很浪费资源     可以在循环外面声明。。。循环里面可以清空再赋值

[解决办法]
看了楼主的代码
1.像这样大量数据操作时,影响到主线程了,必须开线程。
2.大量数据操作不要循环嵌套,一层循环都最好不要。----思路问题

建议
1.开线程处理数据。
2.在执行数据处理的时候关闭界面重绘。可用sendmessage API

        [DllImport("user32")]
        private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, IntPtr lParam);
        private const int WM_SETREDRAW = 0xB;

SendMessage(AddClientContrl.Handle, WM_SETREDRAW, 0, IntPtr.Zero);//禁止该控件重绘
SendMessage(AddClientContrl.Handle, WM_SETREDRAW, 1, IntPtr.Zero);//开启该控件重绘
3.数据绑定后再开启重绘 强制重绘一次
4.处理数据的时候。最好给该数据打好标记。避免循环。控件用tag属性可以存object
5.循环里面尽量少声明变量   很浪费资源     可以在循环外面声明。。。循环里面可以清空再赋值

[解决办法]
timer定时,数据如数据库做个缓冲后再读出。
[解决办法]
首先让界面刷新得慢一点,每秒钟几次,就够了。
其次,那些控件是否一定要放在一个窗体下?把它们按照功能分类,放在不同的窗体下。
这两个应该都能有效解决卡的问题。

热点排行