我已经创建了一个用户控件。在控件中,我有两种方法-发送和接收一些数据。这些方法还会更新位于用户控件上的数据网格。
public void RunTX()
{
tx_run = new Thread(new ThreadStart(SendCanFrames));
if (!tx_run.IsAlive)
{
tx_run.IsBackground = true;
tx_run.Start();
}
}
public void RunRX()
{
rx_run = new Thread(new ThreadStart(ReadCanFrames));
if (!rx_run.IsAlive)
{
rx_run.IsBackground = true;
rx_run.Start();
}
}
private void ReadCanFrames()
{
ushort prev_time_stamp = 0;
while (running)
{
if (CanDevice != null)
CanDevice.Read(ref rx_can_msg, 1, ref read_cnt);
if (read_cnt == 1)
{
read_cnt = 0;
dataGridViewCanRx.Rows[0].Cells[0].Value = rx_can_msg[0].Id.ToString("X");
dataGridViewCanRx.Rows[0].Cells[1].Value = rx_can_msg[0].Size.ToString();
dataGridViewCanRx.Rows[0].Cells[2].Value = BytesToString(rx_can_msg[0].Data);
dataGridViewCanRx.Rows[0].Cells[3].Value = (rx_can_msg[0].TimeStamp - prev_time_stamp).ToString();
prev_time_stamp = rx_can_msg[0].TimeStamp;
}
prev_time_stamp = rx_can_msg[0].TimeStamp;
}
}
private void SendCanFrames()
{
if (tx_can_msg.Length == 0) return;
VSCAN_MSG[] l_msgs = new VSCAN_MSG[2];
while (running)
{
for (int i = 0; i < tx_can_msg.Length; i++)
{
if (can_messages[i].CountRun < can_messages[i].CountMax)
{
can_messages[i].TimeStamp1 = DateTime.Now;
interval = can_messages[i].TimeStamp1 - can_messages[i].TimeStamp2;
if (interval.TotalMilliseconds >= can_messages[i].Period)
{
can_messages[i].TimeStamp2 = DateTime.Now;
l_msgs[0] = tx_can_msg[i];
//send CAN frame
CanDevice.Write(l_msgs, 1, ref written_cnt);
// send immediately
CanDevice.Flush();
can_messages[i].CountRun++;
dataGridViewCanTx.Rows[i].Cells[4].Value = can_messages[i].CountRun.ToString();
}
}
}
}
}
我在主窗体上放置了四个用户控件实例,并启动了所有四个控件。
private void buttonStartAll_Click(object sender, EventArgs e)
{
int can_channel;
for (can_channel = 0; can_channel < 4; can_channel++)
{
if (started[can_channel] == false)
{
if (connected[can_channel] == true)
{
switch (can_channel)
{
case 0:
mainform.userControlCan1.RunTX();
mainform.userControlCan1.RunRX();
started[can_channel] = true;
break;
case 1:
mainform.userControlCan2.RunTX();
mainform.userControlCan2.RunRX();
started[can_channel] = true;
break;
case 2:
mainform.userControlCan3.RunTX();
mainform.userControlCan3.RunRX();
started[can_channel] = true;
break;
case 3:
mainform.userControlCan4.RunTX();
mainform.userControlCan4.RunRX();
started[can_channel] = true;
break;
}
}
}
}
}
所有程序都在运行,但是GUI冻结和数据网格通过跳转进行更新。为什么?
答案 0 :(得分:0)
我建议您着眼于两个关键点:调用和Application.DoEvents。
第一个将帮助您在主线程而不是子线程中更新GUI。 看看:https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.invoke?view=netframework-4.8
Application.DoEvents()方法告诉系统执行其他等待的作业,而不会阻塞某些循环。否则,更新GUI作业将被推迟并且GUI被阻止。这是有关此方法的信息:https://docs.microsoft.com/tr-tr/dotnet/api/system.windows.forms.application.doevents?view=netframework-4.8
private delegate void dlgUpdateRows(object[] rx_can_msg, int tID);
// Write actual type of rx_can_msg instead of object[] in method signature , second parameter should be your thread id if needed
private void UpdateRows(object[] rx_can_msg, int tID =0)
{
try
{
if (this.InvokeRequired)
{
object[] obj = new object[2];
obj[0] = rx_can_msg;
obj[1] = Thread.CurrentThread.ManagedThreadId;
this.Invoke(new dlgUpdateRows(UpdateRows), obj);
}
else
{
//Here update your datagrid using rx_can_msg
}
//This row is important to avoid blocking
Application.DoEvents();
}
catch (Exception ex)
{
//Do error handling
}
}