如何从另一个线程调用控制方法
How to call a control method from another thread
我想从另一个线程调用 RichTextBox.Find()
。我怎样才能做到这一点?
RichTextBox
位于我在表单中使用的 UserControl
中。
我想从另一个线程更新它。我能够使用 Invoke
更改其属性。但是无法弄清楚如何从我的线程中调用 _ucResultRich.rchResult.Find(word, startIndex, RichTextBoxFinds.None);
。
Thread thread=new Thread(thrHighlight);
thread.Start(e.RowIndex);
private void ThrHighlight(object obj)
{
string[] words = ucSearchControls.rdbExact.Checked
? new string[] { ucSearchControls.txtSearch.Text.Trim() }
: ucSearchControls.txtSearch.Text.Split(' ');
foreach (string word in words)
{
int startIndex = 0;
while (startIndex < _ucResultRich.rchResult.TextLength)
{
int wordStartIndex = _ucResultRich.rchResult.Find(word, startIndex, RichTextBoxFinds.None);
if (wordStartIndex != -1)
{
_ucResultRich.rchResult.SelectionStart = wordStartIndex;
_ucResultRich.rchResult.SelectionLength = word.Length;
_ucResultRich.rchResult.SelectionBackColor = Color.Yellow;
}
else
break;
startIndex += wordStartIndex + word.Length;
}
}
}
我该怎么做?
P.S:这是 和那里的@varocarbas 评论
的后续行动
您需要将您的代码与 UI 控件稍微分离,并在外部线程上执行您的业务逻辑并在 Dispatcher.BeginInvoke 或 Invoke 上更新 UI 控件。
例如,您可以将文本框的文本保存在单独的 属性 中,然后在其他线程上执行查找,完成后 post UI 突出显示部分UI 个线程。
这个答案完全专注于展示如何正确使用(即通过最大化其内置功能)BackgroundWorker
(这是我在 [=27= 中写的一些评论的延续) ]) 以提供预期的功能。
要使用这些行下面的代码,请启动一个新的 Winforms 项目并将以下控件添加到主窗体:Button
(button1
带有单击事件 button1
), RichTextBox
(richTextBox1
) 和 BackgroundWorker
(backgroundWorker1
与 DoWork
事件 backgroundWorker1_DoWork
和 ProgressChanged
事件 backgroundWorker1_ProgressChanged
);另请注意 Form1_Load
是主窗体的 Load
事件。
要使用该应用程序,只需在 richTextBox1
中输入任何文本,包括一些硬编码词(即 "word1"、"word2"、"word3"、"word4", "word5"), 单击 button1
并确认它们按预期突出显示。
volatile int curWordStartIndex; //I use this global variable to communication between the progressChanged event and findBit, called from the DoWork event
private void Form1_Load(object sender, EventArgs e)
{
backgroundWorker1.WorkerReportsProgress = true;
}
private void button1_Click(object sender, EventArgs e)
{
//As far as richTextBox1.TextLength provokes a cross-thread error, I pass it as an argument
backgroundWorker1.RunWorkerAsync(richTextBox1.TextLength);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
findBit((int)e.Argument);
}
private void findBit(int textLength)
{
string[] words = new string[] { "word1", "word2", "word3", "word4", "word5" };
foreach (string word in words)
{
int startIndex = 0;
while (startIndex < textLength)
{
//Rather than performing the actions affecting the GUI thread here, I pass all the variables I need to
//the ProgressChanged event through ReportProgress and perform the modifications there.
backgroundWorker1.ReportProgress(0, new object[] { word, startIndex, Color.Yellow });
if (curWordStartIndex == -1) break;
startIndex += curWordStartIndex + word.Length;
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
object[] curVars = (object[])e.UserState;
richTextBox1.SuspendLayout();
string word = (string)curVars[0];
int startIndex = (int)curVars[1];
Color curColor = (Color)curVars[2];
curWordStartIndex = richTextBox1.Find(word, startIndex, RichTextBoxFinds.None);
if (curWordStartIndex != -1)
{
richTextBox1.SelectionStart = curWordStartIndex;
richTextBox1.SelectionLength = word.Length;
richTextBox1.SelectionBackColor = curColor;
}
richTextBox1.ResumeLayout();
}
我想从另一个线程调用 RichTextBox.Find()
。我怎样才能做到这一点?
RichTextBox
位于我在表单中使用的 UserControl
中。
我想从另一个线程更新它。我能够使用 Invoke
更改其属性。但是无法弄清楚如何从我的线程中调用 _ucResultRich.rchResult.Find(word, startIndex, RichTextBoxFinds.None);
。
Thread thread=new Thread(thrHighlight);
thread.Start(e.RowIndex);
private void ThrHighlight(object obj)
{
string[] words = ucSearchControls.rdbExact.Checked
? new string[] { ucSearchControls.txtSearch.Text.Trim() }
: ucSearchControls.txtSearch.Text.Split(' ');
foreach (string word in words)
{
int startIndex = 0;
while (startIndex < _ucResultRich.rchResult.TextLength)
{
int wordStartIndex = _ucResultRich.rchResult.Find(word, startIndex, RichTextBoxFinds.None);
if (wordStartIndex != -1)
{
_ucResultRich.rchResult.SelectionStart = wordStartIndex;
_ucResultRich.rchResult.SelectionLength = word.Length;
_ucResultRich.rchResult.SelectionBackColor = Color.Yellow;
}
else
break;
startIndex += wordStartIndex + word.Length;
}
}
}
我该怎么做?
P.S:这是
您需要将您的代码与 UI 控件稍微分离,并在外部线程上执行您的业务逻辑并在 Dispatcher.BeginInvoke 或 Invoke 上更新 UI 控件。
例如,您可以将文本框的文本保存在单独的 属性 中,然后在其他线程上执行查找,完成后 post UI 突出显示部分UI 个线程。
这个答案完全专注于展示如何正确使用(即通过最大化其内置功能)BackgroundWorker
(这是我在 [=27= 中写的一些评论的延续) ]) 以提供预期的功能。
要使用这些行下面的代码,请启动一个新的 Winforms 项目并将以下控件添加到主窗体:Button
(button1
带有单击事件 button1
), RichTextBox
(richTextBox1
) 和 BackgroundWorker
(backgroundWorker1
与 DoWork
事件 backgroundWorker1_DoWork
和 ProgressChanged
事件 backgroundWorker1_ProgressChanged
);另请注意 Form1_Load
是主窗体的 Load
事件。
要使用该应用程序,只需在 richTextBox1
中输入任何文本,包括一些硬编码词(即 "word1"、"word2"、"word3"、"word4", "word5"), 单击 button1
并确认它们按预期突出显示。
volatile int curWordStartIndex; //I use this global variable to communication between the progressChanged event and findBit, called from the DoWork event
private void Form1_Load(object sender, EventArgs e)
{
backgroundWorker1.WorkerReportsProgress = true;
}
private void button1_Click(object sender, EventArgs e)
{
//As far as richTextBox1.TextLength provokes a cross-thread error, I pass it as an argument
backgroundWorker1.RunWorkerAsync(richTextBox1.TextLength);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
findBit((int)e.Argument);
}
private void findBit(int textLength)
{
string[] words = new string[] { "word1", "word2", "word3", "word4", "word5" };
foreach (string word in words)
{
int startIndex = 0;
while (startIndex < textLength)
{
//Rather than performing the actions affecting the GUI thread here, I pass all the variables I need to
//the ProgressChanged event through ReportProgress and perform the modifications there.
backgroundWorker1.ReportProgress(0, new object[] { word, startIndex, Color.Yellow });
if (curWordStartIndex == -1) break;
startIndex += curWordStartIndex + word.Length;
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
object[] curVars = (object[])e.UserState;
richTextBox1.SuspendLayout();
string word = (string)curVars[0];
int startIndex = (int)curVars[1];
Color curColor = (Color)curVars[2];
curWordStartIndex = richTextBox1.Find(word, startIndex, RichTextBoxFinds.None);
if (curWordStartIndex != -1)
{
richTextBox1.SelectionStart = curWordStartIndex;
richTextBox1.SelectionLength = word.Length;
richTextBox1.SelectionBackColor = curColor;
}
richTextBox1.ResumeLayout();
}