多线程流文档
Multithreaded FlowDocument
当我在单独的线程中 运行 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 绑定到文档 属性 :
<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" />
谢谢。
好吧,坏消息是 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));
...在本例中为文本 属性 添加绑定。我想这可以通过使用 DataTemplates 指定用于每个视图模型元素的控件并在 XAML 等中指定绑定来大大简化。如果正确实现,这将允许您在 GUI 线程中一次创建文档本身加载时间,然后允许您在您喜欢的任何线程中更新文本、颜色等的视图模型属性,而无需重新创建整个文档。
第二种选择是使用其他人已经为您完成这项工作的库,为此我建议您查看 WPF Tookkit's implementation of a bindable RichTextBox.
当我在单独的线程中 运行 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 绑定到文档 属性 :
<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" />
谢谢。
好吧,坏消息是 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));
...在本例中为文本 属性 添加绑定。我想这可以通过使用 DataTemplates 指定用于每个视图模型元素的控件并在 XAML 等中指定绑定来大大简化。如果正确实现,这将允许您在 GUI 线程中一次创建文档本身加载时间,然后允许您在您喜欢的任何线程中更新文本、颜色等的视图模型属性,而无需重新创建整个文档。
第二种选择是使用其他人已经为您完成这项工作的库,为此我建议您查看 WPF Tookkit's implementation of a bindable RichTextBox.