从单独的线程将彩色文本附加到富文本框
本文关键字:文本 彩色 单独 线程 | 更新日期: 2023-09-27 18:26:03
不久前,我在代码项目(链接)上发现了以下代码,它可以帮助我从另一个线程向富文本框添加一些文本:
delegate void UpdateMessageLog(Control ctrl, string text);
public static void UpdateText(Control ctrl, string text)
{
if (ctrl.InvokeRequired)
{
UpdateMessageLog delUpdate = new UpdateMessageLog(UpdateText);
ctrl.Invoke(delUpdate, ctrl, text);
}
else
{
ctrl.Text += text;
}
}
这是必要的,因为我正在WinForms中使用c#开发一个简单的基于UDP的聊天应用程序,并且我的侦听服务器方法正在另一个线程上运行,因此如果收到消息,它的文本将使用上面的代码更新到RTB。这是我的服务器方法:
private void serverThread()
{
UdpClient udpReceiveClient = new UdpClient(8082);
while (true)
{
IPEndPoint ConnectingIPEndPoint = new IPEndPoint(IPAddress.Any, 0);
byte[] receivedBytes = udpReceiveClient.Receive(ref ConnectingIPEndPoint);
string sMessage = Encoding.ASCII.GetString(receivedBytes);
UpdateText(rtbTextWindow, Environment.NewLine + "Sound Desk: " + sMessage);
}
}
后来,我发现了一些代码,可以将彩色文本添加到RTB中,并帮助我用不同的颜色为不同的文本着色:
private void AppendText(RichTextBox box, Color color, string text)
{
int start = box.TextLength;
box.AppendText(text);
int end = box.TextLength;
// Textbox may transform chars, so (end-start) != text.Length
box.Select(start, end - start);
{
box.SelectionColor = color;
// could set box.SelectionBackColor, box.SelectionFont too.
}
box.SelectionLength = 0; // clear
}
下面是我使用它的一个例子——当当前客户端发送消息时,它自己的消息也会添加到RTB:
private void btnSend_Click(object sender, EventArgs e)
{
AppendText(this.rtbTextWindow, Color.GreenYellow, Environment.NewLine + "Front Stage: ");
AppendText(this.rtbTextWindow, Color.Black, txtMsg.Text);
SendOverUDP(txtMsg.Text);
//Clear Text
txtMsg.Clear();
txtMsg.Focus();
}
现在,如果我使用它将彩色文本附加到当前客户端正在发送的RTB,但从不同节点接收到的文本(从服务器线程接收到)需要不同的解决方案,这将非常有效,因为AppendText
方法不检查或处理RTB的"InvokeRequired"方面。
您需要了解的第一件事是,任何用户界面(UI)对象都只能在UI线程上更新。其中包括您对txtMsg的引用。
你可能在一个单独的后台线程上与聊天的另一端进行通信。因此,为了更新您的UI,您必须跳转或调用到UI线程中进行更新。
您的"UpdateText()
"方法为您提供了如何为AppendText执行此操作的所有线索。首先,您甚至不能从后台线程引用UI控件。
此外,作为附带说明,还有一个称为Action
的通用委托,它消除了定义委托的需要,例如UpdateMessageLog委托。
因此,无论何时您希望更新任何控件,都要遵循一个简单的模式,如下所示:
void UpdateControl(object dataToApply)
{
if (myControl.InvokeRequired)
{
myControl.Invoke(new Action<object>(UpdateControl), dataToApply);
}
else
{
//Code goes here to apply the update. This will run on the UI thread,
//such as your call to update your RichTextBox:
AppendText(this.rtbTextWindow, Color.Black, dataToApply);
}
}
有关如何传递不同类型和数量的参数的详细信息,可以查阅Action<>
泛型委托。如果需要从UI控件返回值,则可以使用Func<>
。请注意,我上面使用的类型(object
)只是向您展示一个示例——在您的情况下,您可能希望将其设置为string
。
如果我理解正确的话,您只想让AppendText
像UpdateText
一样具有"线程意识"。模式总是一样的——检查InvokeRequired
,如果是,则创建并调用该方法的委托,否则只执行正常的方法代码。像这个
private void AppendText(RichTextBox box, Color color, string text)
{
if (box.InvokeRequired)
{
box.Invoke(new Action<RichTextBox, Color, string>(AppendText), box, color, text);
return;
}
// The existing code ...
}