0

问题

从串口我收到一个字符流。我收到的流将被 \n 终止。我以如下方式接收串行端口数据:

Serial port Event 1: "123\n456\n789"
Serial port Event 2: "\n0123\n456\n789\n"
Serial port Event 3: "0123\n456\n789\n"

如您所见,我的流在波动,这是非常正常的,因为我使用“当前可用的内容”读取串行端口。

我的问题是我想用 RichTextBox 将它记录到 UI 中。我不能使用 ListBox,因为我需要颜色和字体格式。

第一种方法

在我在下面尝试这个之前,效果很好,直到消息超过大约 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;

几乎可以很好地工作。这种方法的问题是来自串行端口的行在收到 \n 之前不会被粘贴到 UI。这意味着每当通信缓慢时,我必须等待串行流完成包括 \n 在内的整行才能看到它......我想要的是直接看到每个字符。

关于串口的信息

我从 SerialDataReceivedEvent 获得的串行数据,在这种情况下,我使用 comport.ReadExisting() 来进行非阻塞事件。串行数据来自我的具有模拟读数的嵌入式编程板。模拟读数每秒为我提供 20 行,每行包含 20 个字符。我需要在用户界面中读取原始数据,其中必须根据串行消息的前缀将其过滤到其他文本框(例如 err 进入 error , warn 进入警告文本框,但它们都进入活动日志. 活动日志就是这个问题的内容。

4

2 回答 2

0

我找到了一个可行的解决方案,这是我的代码:

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('\0', '\n'); // remove \0 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;

    }));
}
于 2012-06-24T17:25:20.103 回答
0

我希望我能给你一个特定的代码块来处理,但我有一段时间不用做这种输入处理了。

话虽如此,通过将输入缓冲到QueueMSDN 参考)对象中,然后在计时器上轮询队列或响应某些其他事件(也许OnChanged?),您可能会获得更好的性能。

于 2012-06-24T09:40:37.757 回答