【问题标题】:Circular log TextBox for raw serial characters原始序列字符的循环日志文本框
【发布时间】:2012-06-24 09:18:13
【问题描述】:

问题

我从串口接收到一个字符流。我收到的流将被 \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 进入警告文本框,但它们都进入活动日志. 活动日志就是这个问题的内容。

【问题讨论】:

    标签: c# logging serial-port richtextbox


    【解决方案1】:

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

    话虽如此,通过将输入缓冲到 Queue (MSDN reference) 对象中,然后在计时器上轮询队列或响应其他事件(可能是 OnChanged?),您可能会获得更好的性能.

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多