原始串行字符的循环日志文本框



>问题

从串行端口,我收到字符流。我收到的流将由 终止。我接收串口数据的部分如下:

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;
    }));
}

最新更新