前段时间我在代码项目(Link)上找到了以下代码,它帮助我从另一个帖子向我的Rich Text Box添加了一些文本:
<%= f.input :cases, collection: 0..500, label: "Number of new cases of ILD per month (approx)", class: 'form-control' %>
这是必需的,因为我在WinForms中使用c#开发一个简单的基于UDP的聊天应用程序,并且我的监听服务器方法在不同的线程上运行,因此如果收到消息,它的文本将更新为RTB使用上面的代码。这是我的服务器方法:
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;
}
}
然后我发现代码可以让我向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();
}
方法不会检查或处理&#39; InvokeRequired&#39; RTB的方面。
答案 0 :(得分:1)
您首先需要了解的是,任何用户界面(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
。
答案 1 :(得分:1)
如果我理解正确,您只需要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 ...
}