Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ruby-on-rails-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从不同线程更改WPF RichTextBox中文本的颜色_C#_Wpf_Richtextbox_Dispatcher - Fatal编程技术网

C# 从不同线程更改WPF RichTextBox中文本的颜色

C# 从不同线程更改WPF RichTextBox中文本的颜色,c#,wpf,richtextbox,dispatcher,C#,Wpf,Richtextbox,Dispatcher,这可能是一个非常简单的问题,如果有重复的问题,请提前道歉,但我还没有找到关于这个具体问题的任何信息 我对RichTextBox中来自不同线程的文本的特定部分着色有问题。我想在RichTextBox中添加一行文本,同时用指定的颜色为该行着色。我能够附加文本并给它上色,但无法从另一个线程执行此操作,尽管我能够从Dispatcher附加纯文本 private void UpdateTextbox(string message, Color color) { rtbOutput.Dispatch

这可能是一个非常简单的问题,如果有重复的问题,请提前道歉,但我还没有找到关于这个具体问题的任何信息

我对RichTextBox中来自不同线程的文本的特定部分着色有问题。我想在RichTextBox中添加一行文本,同时用指定的颜色为该行着色。我能够附加文本并给它上色,但无法从另一个线程执行此操作,尽管我能够从Dispatcher附加纯文本

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));
        })
    );
}
这是我的密码:

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方法中指定颜色,我可以很好地更改颜色,但如果我将其作为参数传递,则无法更改颜色。

您需要将实际更改工作推回到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

使用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);
        }
    );
}

事实证明,另一个线程拥有的不是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);
}

UI对象只能由UI线程更新。如果您正在使用任务,则可以使用
task.ContinueWith(()=>{//code here},TaskScheduler.FromCurrentSynchronizationContext())这很有用,但它不会改变我的问题,即无法从Dispatcher中访问ApplyPropertyValue函数。如果您在UI线程上创建rtbOutput,这应该对您有效。您是对的,您的方法有效。这并没有解决我的问题,因为我在错误的地方寻找解决方案。这看起来应该是可行的,但我在ApplyPropertyValue函数上得到了相同的错误消息。我使用的SynchronizationContext如下:uiContext.Send(newsendorPostCallback(委托(对象状态){//operations on Richtextbox}),null);我应该用不同的方式吗?在这一点上你不需要使用委托。您可以正常地调用这些方法。把所有的东西都放在你的调度器里。另外,我刚刚用CodePlex的一篇关于类的文章编辑了我的答案,现在它开始工作了。结果我的代码有一个不同于我想象的问题。但是你的答案也很有效,谢谢你的文章,它非常有趣。