>问题
从串行端口,我收到字符流。我收到的流将由 终止。我接收串口数据的部分如下:
Serial port Event 1: "123n456n789"
Serial port Event 2: "n0123n456n789n"
Serial port Event 3: "0123n456n789n"
如您所见,我的流波动,这是非常正常的,因为我读取了带有"当前可用"的串行端口。
我的问题是我想用富文本框将其记录到 UI 中。我无法使用列表框,因为我需要颜色和字体格式。
第一种方法
在我下面尝试之前,效果很好,直到消息超过大约 30.000 行文本。UI 无响应。这是代码:
uiTextActivity.SelectionFont = new Font(uiTextActivity.SelectionFont, FontStyle.Bold);
uiTextActivity.SelectionColor = LogMsgTypeColor[(int)msgtype];
uiTextActivity.AppendText(msg);
uiTextActivity.ScrollToCaret();
后来我使用它作为快速修复,在 2000 行之后清除框:
if ((int.Parse(uiLabelCounterActivity.Text) + 1) > 2000)
uiTextBoxResetActivity();
我想保留大约 500 行的历史。但是通过上面的快速修复,当计数器达到 2000 时,我完全丢失了我的日志。
我认为我需要的是一个圆形的FIFO文本框。所以我可以在 500 行后删除最旧的日志并附加新的日志。
第二种方法
我也试过这个(请注意,在这种情况下,最新的日志条目在文本框的顶部和最旧的条目在下面)
msg = msgToPasteWhenComplete + msg;
int c = 0; // c=zero if no newline, 1 for single newline, 2 for 2times newline and so on
int latestTermination = 0;// store the point where n is found
for (int e = 0; e < msg.Length; e++)
{
if (msg[e] == 'n')
{
c++;
latestTermination = e+1;
}
}
// contains strings all terminated with n
string msgToPaste = msg.Substring(0, latestTermination);
// contains string that is not complete (not yet terminated with n)
msgToPasteWhenComplete = msg.Substring(latestTermination, msg.Length - latestTermination);
string previous = msgToPaste + uiTextActivity.Text;
if (previous.Length > maxDisplayTextLength)
{
string debugInfo3 = previous.Substring(0, maxDisplayTextLength);
uiTextActivity.Text = debugInfo3;
}
else
uiTextActivity.Text = previous;
这几乎非常有效。此方法的问题是,在收到 之前,来自串行端口的行不会粘贴到 UI 中。这意味着每当通信速度很慢时,我将不得不等待串行流完成整行,包括 才能看到它......我想要的是直接看到每个角色。
有关串口的信息
我从SerialDataReceivedEvent获得的串行数据,在该事件中,我使用comport。ReadExisting() 具有非阻塞事件。串行数据来自我的嵌入式编程板,该编程板具有模拟读数。模拟读数每秒为我提供 20 行,每行包含 20 个字符。我需要在用户界面中读取原始数据,其中必须根据串行消息的前缀将其过滤到其他文本框(例如 err 转到错误,警告转到警告文本框,但它们都转到活动日志。活动日志是这个问题的内容。
我能给你一个特定的代码块来处理,但我有一段时间不必做这种输入处理了。
话虽如此,通过将输入缓冲到 Queue
(MSDN 引用)对象中,然后在计时器上轮询队列或通过响应某些其他事件(可能是OnChanged
?),您可能会获得更好的性能。
我找到了一个有效的解决方案,这是我的代码:
private const int maxDisplayTextLength = 5000;
private string splitString = "";
private int activityCount = 0;
private string errorMessageBox = "";
private bool errorMessageBoxNeedUpdate = true;
private int errorMessageBoxCount = 0;
private string filteredMessageBox = "";
private int filteredMessageCount = 0;
private bool filteredMessageBoxNeedUpdate = true;
private string activityLogFilterKeyword = "Warning";
string logHelperStringMaxSizeLimiter(string input)
{
// check if our buffer isn't getting bigger than our specified max. length
if (input.Length > maxDisplayTextLength)
{
// discard the oldest data in our buffer (FIFO) so we have room for our newest values
input = input.Substring(input.Length - maxDisplayTextLength);
}
return input;
}
private void logHelperIncoming(string msg)
{
msg = msg.Replace(' ', 'n'); // remove NULL characters as they have special meanings in C# RichTextBox
// add the new received string to our buffer
splitString += msg;
// filter out special strings
int searchIndexStart = splitString.Length - msg.Length;
for (int e = searchIndexStart; e < splitString.Length; e++)
{
if (splitString[e] == 'n')
{
activityCount++;
string subString = splitString.Substring(searchIndexStart, e - searchIndexStart) + "n";
searchIndexStart += e - searchIndexStart + 1; // update searchindex for next search
string filterError = "error";
// filter messages that start with error
if (subString.Length > filterError.Length) // for this filter, the length should be at least length of error
{
if (String.Compare(subString, 0, filterError, 0, 4, true) == 0)
{
errorMessageBox += subString;
errorMessageBoxNeedUpdate = true;
errorMessageBoxCount++;
}
}
// filter messages that start with XXX
if (subString.Length > activityLogFilterKeyword.Length && activityLogFilterKeyword.Length != 0) // for this filter, the length should be at least length of error
{
if (String.Compare(subString, 0, activityLogFilterKeyword, 0, activityLogFilterKeyword.Length, true) == 0)
{
filteredMessageBox += subString;
filteredMessageBoxNeedUpdate = true;
filteredMessageCount++;
}
}
}
}
}
// outputs to main activity textbox
private void Log(LogMsgType msgtype, string msg)
{
if (msgtype == LogMsgType.Incoming || msgtype == LogMsgType.Normal)
{
logHelperIncoming(msg);
}
else if (msgtype == LogMsgType.Outgoing)
{
}
splitString = logHelperStringMaxSizeLimiter(splitString);
filteredMessageBox = logHelperStringMaxSizeLimiter(filteredMessageBox);
errorMessageBox = logHelperStringMaxSizeLimiter(errorMessageBox);
uiTextActivity.Invoke(new EventHandler(delegate
{
// time to post our updated buffer to the UI
uiTextActivity.Text = splitString;
uiTextActivity.Update();
// scroll to the newest data only if user has no focus on the
uiTextActivity.SelectionStart = uiTextActivity.TextLength; // make sure view is to the latest
uiTextActivity.ScrollToCaret();
uiLabelCounterActivity.Text = activityCount.ToString();
if (errorMessageBoxNeedUpdate)
{
errorMessageBoxNeedUpdate = false;
uiTextActivity.SelectionColor = Color.Red;
// time to post our updated buffer to the UI
uiTextboxErrorLog.Text = errorMessageBox;
// scroll to the newest data only if user has no focus on the
uiTextboxErrorLog.SelectionStart = uiTextboxErrorLog.TextLength; // make sure view is to the latest
uiTextboxErrorLog.ScrollToCaret();
uiLabelCounterError.Text = errorMessageBoxCount.ToString();
}
if (filteredMessageBoxNeedUpdate)
{
filteredMessageBoxNeedUpdate = false;
// time to post our updated buffer to the UI
uiTextboxFilteredLog.Text = filteredMessageBox;
// scroll to the newest data only if user has no focus on the
uiTextboxFilteredLog.SelectionStart = uiTextboxFilteredLog.TextLength; // make sure view is to the latest
uiTextboxFilteredLog.ScrollToCaret();
uiLabelCounterFiltered.Text = filteredMessageCount.ToString();
}
// extract value from filter and store to filter
activityLogFilterKeyword = uiTextboxFilterKeyword.Text;
}));
}