所以我正在从我的 arduino 读取一个恒定的串行数据流来验证我程序中的一些东西。但是显示这些会锁定 UI 线程。所以我的“解决方案”是制作一个缓冲区来保存串行数据,然后使用计时器以间隔而不是恒定流将数据放在 UI 线程上。
我的代码:
public partial class ConsoleWindow : Window
{
private SerialPort _serialPort;
private List<string> bufferStrings = new List<string>();
private readonly DispatcherTimer timer = new DispatcherTimer();
public ConsoleWindow(ref SerialPort serialPort)
{
InitializeComponent();
if (serialPort != null)
{
timer.Interval = new TimeSpan(0,0,0,0,80);
timer.Tick += PopQueue;
_serialPort = serialPort;
_serialPort.DataReceived += DataReceived;
timer.Start();
}
}
private void PopQueue(object sender, EventArgs e)
{
var queue = bufferStrings;
foreach (var queueString in queue)
{
AppendText(queueString);
}
bufferStrings.Clear();
}
private void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (_serialPort != null)
{
bufferStrings.Add(((SerialPort)sender).ReadLine());
//AppendText(((SerialPort) sender).ReadLine());
}
}
public void AppendText(string text)
{
Application.Current.Dispatcher.Invoke(() =>
{
if (Output.Inlines.Count > 100)
{
Output.Inlines.Remove(Output.Inlines.FirstInline);
}
Output.Inlines.Add(text);
ScrollViewer.ScrollToBottom();
});
}
}
问题是我得到一个异常:System.InvalidOperationException: 'Collection was modified;枚举操作可能无法执行。'
。我知道为什么会这样,但我不知道如何正确地做到这一点。也不知道用谷歌搜索什么。
您可以采取以下两种解决方案来防止 InvalidOperationException
:
- 在遍历其内容之前将缓冲区复制到一个新列表。您可以通过调用
var queue = bufferStrings.ToList();
请注意,您必须包含 using System.Linq;
才能使用 ToList()
.
通过用 lock
关键字包围它来使迭代线程安全:
private void PopQueue(object sender, EventArgs e)
{
lock(bufferStrings)
{
foreach (var queueString in bufferStrings)
{
AppendText(queueString);
}
bufferStrings.Clear();
}
}
private void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (_serialPort != null)
{
lock(bufferStrings)
{
bufferStrings.Add(((SerialPort)sender).ReadLine());
//AppendText(((SerialPort) sender).ReadLine());
}
}
}
我是一名优秀的程序员,十分优秀!