【问题标题】:Multithreaded FlowDocument多线程流文档
【发布时间】:2019-01-06 02:38:38
【问题描述】:

当我在单独的线程中运行 FlowDoc 时出现异常,即使使用调度程序调用也无法解决问题。 我读了一些关于将flowdoc序列化为xdoc并序列化回来的文章,但这听起来很麻烦。 我已经被这个问题困扰了2天,我的头裂了,请帮忙:)

这是我的代码

 new Thread(() =>
        {
            Thread.CurrentThread.IsBackground = true;
            for (int i = 0; i < 10; i++)
            {
                 mcFlowDoc = new FlowDocument();
                 // Create a paragraph with text
                 Paragraph para = new Paragraph();
                 para.Inlines.Add(new Bold(new Run("This is a Title \n")));
                 para.Inlines.Add(new Run("I am a flow document. Would you like to edit me? \n"));

                 Dispatcher.CurrentDispatcher.Invoke((Action)(() =>
                 {
                    mcFlowDoc.Blocks.Add(para);
                 }));
            }
        }).Start();

还有我的 XAML,我只是使用普通的 RichTextBox 并将 flowdoc 绑定到 Document 属性:

<fsrtb:FsRichTextBox x:Name="EditBox" Document="{Binding mcFlowDoc}" Grid.Row="0" Margin="10,10,10,91" ToolbarBackground="#FFD2CB84" ToolbarBorderBrush="#FFC6BE75" ToolbarBorderThickness="1,1,1,0" CodeControlsVisibility="Collapsed" />

谢谢。

【问题讨论】:

  • 所有文档元素(如 FlowDocument 或 Paragraph)都派生自 DispatcherObject,因此具有线程关联性。不能在创建它们的线程之外访问它们。换句话说,所有这些元素都必须在 UI 线程中创建和修改,即 RichTextBox 的创建位置。
  • 你得到的确切异常是什么?
  • 还要注意Dispatcher.CurrentDispatcher为你的线程创建了一个新的Dispatcher,它不是你应用的UI线程的Dispatcher。但是,即使使用Application.Current.Dispatcher,您的代码也无法运行。
  • @Clemens 谢谢你的回复,我知道,这就是我来这里找工作的原因:)
  • 没有。不要在后台线程中创建文档元素。如果创建文档内容有耗时操作,使用 async/await,但在 UI 线程中创建文档元素。

标签: c# wpf multithreading mvvm richtextbox


【解决方案1】:

好吧,坏消息是 RTB 不直接支持数据绑定。 MSDN 网站上有一个页面解释了他们为什么这样做,但无论哪种方式,这都是一个深思熟虑的设计决定。

据我所知,您有两种选择。首先是推出自己的解决方案。这基本上涉及为要显示的所有项目类型创建视图模型,在视图模型中维护它们的集合,并使用行为绑定到它并填充 RTB。您的行为还必须手动设置绑定,而不是这样:

para.Inlines.Add(new Bold(new Run("This is a Title \n")));

...你应该这样做:

var binding = new Binding
{
    Path = new PropertyPath("BackgroundProperty"),
    Mode = BindingMode.OneWay,
    UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
    };
var run = new Run();
BindingOperations.SetBinding(run, Run.TextProperty, binding);
para.Inlines.Add(new Bold(run));

...在这种情况下为 text 属性添加绑定。我想这可以通过使用 DataTemplates 来指定要用于每个视图模型元素的控件并指定 XAML 等中的绑定来大大简化。如果实施正确,这将允许您在加载时在 GUI 线程中创建文档本身,然后允许您在您喜欢的任何线程中更新文本、颜色等的视图模型属性,而无需重新创建整个文档。

第二种选择是使用其他人已经为您完成这项工作的库,为此我建议您查看WPF Tookkit's implementation of a bindable RichTextBox

【讨论】:

  • 非常感谢,我已经使用了 Toolkit,它工作正常。我还通过在 dispatcher.Invok 中简单地包装整个文档创建来使它工作!我不知道这是否是正确的方法,但它有效!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-14
  • 1970-01-01
  • 2010-12-12
  • 1970-01-01
  • 2013-10-18
  • 2023-03-13
相关资源
最近更新 更多