我不敢相信以前没有问过,但我在这里找不到参考。对不起,如果我错过了!!从线程更新rtb.Text有很多,但很少或没有获得rtb.Text。
我需要从另一个线程的UI线程上的richtextbox获取文本值,然后能够循环遍历同一个richtextbox的每一行。
我想Invokes和代表是必需的,但如何制作它们?
作为一个例子,代码,如果它在同一个线程中,将是这样的:
private void checkRtbEntries()
{
if (rtb.Text != "")
{
foreach (string textLine in rtb.Lines)
{
// do some things in the background thread
// based on the rtb line content...
}
}
}
但是,checkRtbEntries()是从Backgroundworker线程中调用的,而rtb是在UI线程中,因此抛出了无效的跨线程操作。
运行BackgroundWorker线程时,可以选择将参数传递给它,另一个线程可以引用该参数并使用:
myWorker.RunWorkerAsync(rtb.Text);
在DoWork
事件中,将参数强制转换为字符串并对其执行操作。
var myRtbText = e.Argument.ToString();
这样,您的后台线程实际上从未触及UI线程。
如果您需要在后台工作程序运行时对主线程上的元素进行更改,则需要使用ProgressChanged
事件。
由于RichTextBox
事件中没有对DoWork
的引用(只是其Text
属性的内容),因此您无法在原始文本框中调用Lines
属性。
你应该能够很容易地模拟它(实际的Lines
属性测试“\ r”,“\ r \ n”和“\ n”,但是Environment.NewLine
应该为你解决这个问题):
var allLines
= myRtbText.Split(new[] {Environment.NewLine}, StringSplitOptions.None);
(如果要忽略空行,请使用StringSplitOptions.RemoveEmptyEntries。)
这是从后台跳转到UI线程的常用方法(对于每个控件)
private delegate void checkRichTextBoxDelegate();
private void checkRtbEntries()
{
if (this.rtb.InvokeRequired)
{
checkRichTextBoxDelegate checkEntries = new checkRichTextBoxDelegate(checkRtbEntries);
this.Invoke(checkRtbEntries);
}
else
{
.... do your work on the RichTextBox, you are on the UI thread
}
}