这可能是一个非常简单的问题,如果有重复,请提前抱歉,但我还没有找到有关此特定问题的任何内容。
我在从不同的线程中对RichTextBox中文本的特定部分进行着色时遇到问题。我想在RichTextBox中附加一行文本,同时用指定颜色为该行着色。我能够附加文本和颜色,但是从其他线程无法这样做,尽管我能够从Dispatcher附加纯文本。
这是我的代码:
private void UpdateTextbox(string message, Brush color)
{
rtbOutput.Dispatcher.Invoke((Action)(() =>
{
rtbOutput.Selection.Select(rtbOutput.Document.ContentEnd, rtbOutput.Document.ContentEnd);
rtbOutput.Selection.Text = message;
rtbOutput.Selection.ApplyPropertyValue(TextElement.ForegroundProperty, color);
})
);
}
当我尝试从另一个线程运行它时,我收到一条错误消息,告诉我该对象无法访问,因为它属于另一个线程。我该如何解决这个问题?
编辑:似乎RichTextBox不是问题,但是Brush对象是,因为如果我在Invoke方法中指定它,我可以更改颜色,但如果我将它作为参数传递则不能。
答案 0 :(得分:1)
事实证明,不是另一个线程拥有的RichTextBox,而是Brush对象。如果我只是将Color对象传递给方法并将其转换为Dispatcher中的SolidColorBrush,我设法让它与下面的所有解决方案一起工作。
private void UpdateTextbox(string message, Color color)
{
rtbOutput.Dispatcher.Invoke((Action)(() =>
{
TextRange range = new TextRange(rtbOutput.Document.ContentEnd, rtbOutput.Document.ContentEnd);
range.Text = message;
range.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush((Color)color));
})
);
}
它也适用于pquest建议的代码:
private void UpdateTextbox(string message, Brush color)
{
uiContext.Send(o =>
{
TextRange range = new TextRange(rtbOutput.Document.ContentEnd, rtbOutput.Document.ContentEnd);
range.Text = message;
range.ApplyPropertyValue(TextElement.ForegroundProperty, color);
}, null);
}
答案 1 :(得分:0)
您需要将实际的更改工作重新推送到GUI线程。在启动应用程序期间,您可以运行:
SynchronizationContext ctxt = SynchronizationContext.Current;
然后将你的多线程代码传递给它。然后使用它:
//Code that determines the color to use
Color clr = result;
ctxt.Send((clr_obj) =>
{
//Code to set color
}, clr);
编辑:
这是一篇很好的文章,更深入地解释了SyncronizationContext
:Article
答案 2 :(得分:0)
您使用Dispatcher进入了正确的轨道,但您并不总是需要调用Invoke。我使用以下扩展方法来处理这类事情:
public static void InvokeIfNeeded(this Dispatcher dispatcher, Action action)
{
if (dispatcher == null || dispatcher.CheckAccess())
action();
else
dispatcher.Invoke(action, DispatcherPriority.Normal);
}
您可以按如下方式使用它:
private void UpdateTextbox(string message, Brush Color)
{
rtbOutput.Dispatcher.InvokeIfNeeded(() =>
{
rtbOutput.Selection.Select(rtbOutput.Document.ContentEnd, rtbOutput.Document.ContentEnd);
rtbOutput.Selection.Text = message;
rtbOutput.Selection.ApplyPropertyValue(TextElement.ForegroundProperty, Color);
}
);
}