读书人

百分有关问题 C#一个困扰了好几天的有

发布时间: 2013-12-23 14:30:52 作者: rapoo

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

读书人网 >C#

热点推荐