我的目标是在定制系统上监视gsm模块的RX / TX通信。 为此,我在计算机和WPF c#应用程序上使用2个串行端口。 通过特定命令,gsm模块与系统之间的通信可以更改为9600bds,57600bds或125000bds。 使用9600和57600,没问题。 但是当com速度为125000时,我的UI冻结了。 我已经阅读了很多有关用Action,Delegate,dispatcher冻结UI的帖子,但是它不起作用,而且我不知道如何解决问题。
在这里,我现在正在做什么:
这里有一些代码来说明我如何进行:
// queue to store data read on serial port before display
Queue<QueueElement> queueList;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
initPorts();
queueList = new Queue<QueueElement>();
QueueConsumerProcessRunning = false;
queueConsumer();
}
private void initPorts()
{
mySerialPort1.DataReceived += new SerialDataReceivedEventHandler(SerialPort_DataReceived);
mySerialPort2.DataReceived += new SerialDataReceivedEventHandler(SerialPort_DataReceived);
// ...
}
// data on serial port
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Monitor.Enter(queueList);
try
{
// create a queue element and add it to the queue
// ...
queueList.Enqueue(queueSingleElement);
}
finally
{
Monitor.Exit(queueList);
}
}
private void queueConsumer()
{
Thread backgroundThread = new Thread(
new ThreadStart(() =>
{
while (true) // always alive
{
if ((QueueConsumerProcessRunning == false) && (queueList.Count > 0))
{
Dispatcher.Invoke(() => { QueueCount.Text = queueList.Count.ToString(); });
QueueConsumerProcessRunning = true;
QueueElement Qelem;// = new QueueElement();
Monitor.Enter(queueList);
try
{
// get alodest element
Qelem = queueList.Peek();
// remove oldest element
queueList.Dequeue();
}
finally
{
Monitor.Exit(queueList);
}
// call method to display data
AddDataMethod(buildSerialElement(Qelem.SerialPortName, Qelem.ReadBytes, Qelem.EventHour));
QueueConsumerProcessRunning = false;
}
Thread.Sleep(100);
}
}
)); // backgroundThread
backgroundThread.IsBackground = true;
backgroundThread.Start();
}
// display received data
// when incoming data is from the same serial port of last received data: add data on last written row except if it's a carriage return
private void AddDataMethod(SerialElement elem)
{
if (!Dispatcher.CheckAccess()) // CheckAccess returns true if you're on the dispatcher thread this.ListBoxSpy.Disp...
{
Dispatcher.Invoke(new AddDataDelegate(AddDataMethod), elem);
return;
}
// update List<SerialElement>
// ...
// and call the function to update item displayed on UI
refreshDisplay();
}
// refresh display
private void refreshDisplay()
{
// create a list of ListBoxRowItem
// ...
// and display the list on ListBox UI
ListBoxSpy.ItemsSource = myListBoxRows;
}
还有ListBox的xaml部分:
<ListBox Name="ListBoxSpy" HorizontalAlignment="Stretch" Margin="0,100,0,0" VerticalAlignment="Stretch" FontFamily="Courier New" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Message}" Foreground="{Binding MessageColor}" VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.VirtualizationMode="Recycling" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
我使用Visual Studio Community 2017。
答案 0 :(得分:0)
我认为您的Queue有竞赛条件。我假设QueueConsumerTimedEvent在UI线程上运行。 while循环可能永远运行,因为它正在检查queueList.Count> 0,但是在处理顶层项目时,DataReceived线程正在向队列添加更多项目。因此它永远不会达到零,因此会阻塞UI线程。
您至少应该移动显示器。输入以适应,但这样会冒丢失或延迟传入数据的风险。可能应该先出队,以便您可以快速释放Monitor,然后处理出队的项目。