WPF RichTextBox的文档创建线程问题 [英] WPF RichTextBox Document Creation Threading Issue

查看:132
本文介绍了WPF RichTextBox的文档创建线程问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个有点问题的一个RTB和文档生成的问候线程。

在对RTB TextChanged事件触发,一个新的THEAD被创建,文档生成被卸载到这一点。这可能需要几秒钟,以阻塞调用,所以它真正需要的是在另一个线程保持用户界面响应。

我遇到的问题是一个例外,当我尝试将新生成的文档添加到文件 RTB的财产。 (调用线程不能访问此对象,因为不同的线程拥有它。)的这是不是因为忘记使用 Dispatcher.Invoke ,因为多数民众赞成其中产生的异常,但因为我的线程不是UI线程等创建的FlowDocument /款/运行情况(我认为?)。

有没有办法实现我要找的吗?

更新

 私人无效rtbQuery_TextChanged(对象发件人,TextChangedEventArgs E)
    {
        System.Diagnostics.Debug.WriteLine(需要更新;上线:+ System.Threading.Thread.CurrentThread.ManagedThreadId);

        backgroundWorker.RunWorkerAsync();
    }

    私人无效backgroundWorker_DoWork(对象发件人,System.ComponentModel.DoWorkEventArgs E)
    {
        System.Diagnostics.Debug.WriteLine(生成;上线:+ System.Threading.Thread.CurrentThread.ManagedThreadId);

        DocumentGenerator DGEN =新DocumentGenerator();
        字符串QUERYTEXT = getQueryText();

        e.Result = dgen.GenerateDocument(QUERYTEXT);
    }

    私人无效backgroundWorker_RunWorkerCompleted(对象发件人,System.ComponentModel.RunWorkerCompletedEventArgs E)
    {
        System.Diagnostics.Debug.WriteLine(分配;上线:+ System.Threading.Thread.CurrentThread.ManagedThreadId);

        FlowDocument的DOC =(的FlowDocument)e.Result;
        txtQuery.Document =文档; //!调用线程不能访问此对象,因为不同的线程拥有它
    }
 


 >需要更新;对螺纹:9
>生成;上线:10
>分配;对螺纹:9
 


更新#2 - 一个解决方案

(排序)

所以,作为@乔恩·米切尔指出的那样,我不能更新我的RTB在UI线程上,用另一个线程创建的对象。有一个很简单的解决方案,这需要最少code修改,来解决这虽然和我张贴起来,以节省未来的人的麻烦。简单地说明,对象图时另一个线程上创建,然后转换为XAML。然后,UI线程这个XAML转换回对象图,在自己的线程,一切工作都OK。

 私人无效backgroundWorker_DoWork(对象发件人,System.ComponentModel.DoWorkEventArgs E)
    {
        DocumentGenerator DGEN =新DocumentGenerator();
        字符串QUERYTEXT = getQueryText();

        dgen.GenerateDocument(QUERYTEXT); //启动代
        e.Result = DGEN; //注意,我传递的发电机,而不是文件
    }

    私人无效backgroundWorker_RunWorkerCompleted(对象发件人,System.ComponentModel.RunWorkerCompletedEventArgs E)
    {
        DocumentGenerator DGEN =(DocumentGenerator)e.Result;
        txtQuery.Document = dgen.GetFlowDocument();
    }
 

在DocumentGenerator类

 公共无效GenerateDocument(字符串数据)
    {
        ... //建立文件DOM

        //返回documentDOM; //用来回到这里生成的项目。
        documentXAML = System.Windows.Markup.XamlWriter.Save(documentDOM); //序列化DOM为XAML
    }
    公众的FlowDocument GetDocument()
    {
        对象result = System.Windows.Markup.XamlReader.Parse(documentXAML); //从XAML构建DOM
        返回(FlowDocument的)结果;
    }
 

解决方案

我认为这个问题是因为的FlowDocument 的DependencyObject 这是不冻结,因此,不能在一个线程创建,然后在不同的一个使用。我认为它是因为当的FlowDocument 其他线程上创建它有不同的调度员,到RTB。

有一个工作围绕这个这里

I'm having a bit of an issue with a RTB and document generation in regards to threads.

When the TextChanged event fires on the RTB, a new thead is created, and the document generation is offloaded to this. This can take a couple of seconds, with blocking calls, so it really needs to be on another thread to keep the UI responsive.

The problem I'm having is an exception when I try to add the newly generated document to the Document property of the RTB. ( The calling thread cannot access this object because a different thread owns it.) This is not due to forgetting to use Dispatcher.Invoke, as thats where the exception is generated, but because I'm creating the FlowDocument/Paragraph/Run instances on a thread other than the UI thread(I think??).

Is there a way to achieve what I'm looking for here?

Update

    private void rtbQuery_TextChanged(object sender, TextChangedEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("Requires update; on thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId);

        backgroundWorker.RunWorkerAsync();
    }

    private void backgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("Generating; on thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId);

        DocumentGenerator dgen = new DocumentGenerator();
        string queryText = getQueryText();

        e.Result = dgen.GenerateDocument(queryText);
    }

    private void backgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("Assigning; on thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId);

        FlowDocument doc = (FlowDocument)e.Result;
        txtQuery.Document = doc; // ! The calling thread cannot access this object because a different thread owns it
    }


>Requires update; on thread:9
>Generating; on thread:10
>Assigning; on thread:9


Update #2 - A solution

(of sorts)

So, as @Jon Mitchell pointed out, I cant update my RTB on the UI thread, with an object created on another thread. There is a very simple solution, that requires minimal code change, to work around this though, and i'm posting it up to save future people the hassle. Briefly explained, an object graph is created on the other thread, and then converted to XAML. The UI thread then converts this XAML back to the object graph, in its own thread, and everything works a-ok.

    private void backgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
    {
        DocumentGenerator dgen = new DocumentGenerator();
        string queryText = getQueryText();

        dgen.GenerateDocument(queryText); // start generation
        e.Result = dgen; // note, i'm passing the generator, not the document
    }

    private void backgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
    {
        DocumentGenerator dgen = (DocumentGenerator)e.Result;
        txtQuery.Document = dgen.GetFlowDocument(); 
    }

In DocumentGenerator class

    public void GenerateDocument(string data)
    {
        ... // build up the document DOM

        // return documentDOM; // used to return the generated item here.
        documentXAML = System.Windows.Markup.XamlWriter.Save(documentDOM); // serialize the DOM to XAML
    }
    public FlowDocument GetDocument()
    {
        object result = System.Windows.Markup.XamlReader.Parse(documentXAML); // build DOM from XAML
        return (FlowDocument)result;
    }

解决方案

I think the issue is because the FlowDocument is a DependencyObject which isn't freezable and therefore can't be created on one thread and then used on a different one. I think its because when the FlowDocument is created on the other thread it has a different dispatcher, to the RTB.

There is a work around for this here.

这篇关于WPF RichTextBox的文档创建线程问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆