C# WinForms:如何在窗体中嵌入可输出的控制台?
WinForms内嵌支持ASCII颜色的控制台实现方案
核心思路
基于RichTextBox构建自定义控件,解析WebSocket传来的ANSI ASCII颜色转义代码,将其转换为富文本格式展示,同时实现文本输入发送功能。
实现步骤
1. 自定义控制台控件
创建继承自RichTextBox的控件,封装颜色解析和文本追加逻辑:
using System; using System.Text.RegularExpressions; using System.Windows.Forms; public class EmbeddedConsole : RichTextBox { private static readonly Regex AnsiColorRegex = new Regex(@"(\x1b\[[0-9;]*m)", RegexOptions.Compiled); public EmbeddedConsole() { ReadOnly = false; Multiline = true; ScrollBars = RichTextBoxScrollBars.Vertical; WordWrap = false; Font = new System.Drawing.Font("Consolas", 9); } public void AppendConsoleText(string text) { if (InvokeRequired) { Invoke(new Action<string>(AppendConsoleText), text); return; } var segments = AnsiColorRegex.Split(text); foreach (var segment in segments) { if (string.IsNullOrEmpty(segment)) continue; if (segment.StartsWith("\x1b[")) { ApplyAnsiColor(segment); continue; } AppendText(segment); } SelectionStart = TextLength; ScrollToCaret(); } private void ApplyAnsiColor(string ansiCode) { var codePart = ansiCode.Substring(2, ansiCode.Length - 3); var codes = codePart.Split(';'); foreach (var code in codes) { switch (code) { case "0": SelectionColor = System.Drawing.Color.Black; SelectionBackColor = System.Drawing.Color.White; break; case "30": SelectionColor = System.Drawing.Color.Black; break; case "31": SelectionColor = System.Drawing.Color.Red; break; case "32": SelectionColor = System.Drawing.Color.Green; break; case "33": SelectionColor = System.Drawing.Color.Yellow; break; case "34": SelectionColor = System.Drawing.Color.Blue; break; case "35": SelectionColor = System.Drawing.Color.Magenta; break; case "36": SelectionColor = System.Drawing.Color.Cyan; break; case "37": SelectionColor = System.Drawing.Color.Gray; break; } } } public string GetAndClearInput() { var currentLine = GetLineFromCharIndex(SelectionStart); var lineStart = GetFirstCharIndexFromLine(currentLine); var inputText = Text.Substring(lineStart); Select(lineStart, TextLength - lineStart); SelectedText = ""; return inputText.Trim(); } }
2. 集成WebSocket收发逻辑
在窗体中初始化WebSocket,对接自定义控制台控件:
using System.Net.WebSockets; using System.Text; using System.Threading; public partial class MainForm : Form { private ClientWebSocket _webSocket; private EmbeddedConsole _consoleBox; public MainForm() { InitializeComponent(); _consoleBox = new EmbeddedConsole(); _consoleBox.Dock = DockStyle.Fill; Controls.Add(_consoleBox); var sendBtn = new Button { Text = "发送", Dock = DockStyle.Bottom }; sendBtn.Click += SendBtn_Click; Controls.Add(sendBtn); ConnectWebSocketAsync(); } private async void ConnectWebSocketAsync() { _webSocket = new ClientWebSocket(); try { await _webSocket.ConnectAsync(new Uri("ws://your-websocket-server-url"), CancellationToken.None); _consoleBox.AppendConsoleText("已连接到WebSocket服务器\n"); var buffer = new byte[1024 * 4]; while (_webSocket.State == WebSocketState.Open) { var result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None); var message = Encoding.UTF8.GetString(buffer, 0, result.Count); _consoleBox.AppendConsoleText(message); } } catch (Exception ex) { _consoleBox.AppendConsoleText($"连接异常:{ex.Message}\n"); } } private async void SendBtn_Click(object sender, EventArgs e) { if (_webSocket?.State != WebSocketState.Open) { _consoleBox.AppendConsoleText("WebSocket未连接\n"); return; } var inputText = _consoleBox.GetAndClearInput(); if (string.IsNullOrEmpty(inputText)) return; var buffer = Encoding.UTF8.GetBytes(inputText + "\n"); await _webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None); } }
3. 关键注意事项
- 线程安全:WebSocket接收在后台线程,必须通过
Invoke切换到UI线程操作控件,避免跨线程异常。 - ANSI扩展支持:示例仅实现基础前景色,可扩展
ApplyAnsiColor方法支持背景色、粗体、下划线等更多ANSI样式。 - 性能优化:若消息量较大,可批量缓存文本后再一次性追加,减少UI更新频率避免卡顿。
内容的提问来源于stack exchange,提问作者user19969621
相关产品推荐
相关产品推荐

