1

拥有一个大多数属性非常轻量级的对象 - 最多 200 个字符的文本。一个属性是 FlowDocument,它可能很大并且想要异步检索它。当我设置 Async = True 并显示以下消息时它失败:“调用线程无法访问此对象,因为不同的线程拥有它。”

    <FlowDocumentReader Name="FlowDocumentPageViewer1" HorizontalAlignment="Stretch" 
        Document="{Binding Source={x:Static Application.Current}, Path=MyGabeLib.Search.SelectedDoc.DocFlowDocument, Mode=OneWay, IsAsync=True}" />

Production Get 更复杂,但在 IsAsyc True 上同样失败,即使使用简单的硬编码 FlowDocument。

    public FlowDocument DocFlowDocument
    {
        get
        {
            FlowDocument docFlowDocumentFast = new FlowDocument();
            Paragraph p = new Paragraph();
            Run r = new Run();
            r.Foreground = System.Windows.Media.Brushes.Red;
            r.Text = "Hard Code Simple FlowDocument";
            p.Inlines.Add(r);
            docFlowDocumentFast.Blocks.Add(p);
            return docFlowDocumentFast;
        }
    {

它确实调用 SelectedDoc.DocFlowDocument 并返回文档!使用 IsAsync = False 它运行得很好。我认为问题在于静态源,但显然我不知道如何解决它。

    public partial class App : Application
    {
        private static GabeLib staticGabeLib = new GabeLib();

        private GabeLib myGabeLib = staticGabeLib;

        public GabeLib MyGabeLib
        { get { return myGabeLib; } }


        public static GabeLib StaticGabeLib
        { get { return staticGabeLib; } }
    }

当 GabeLib 启动时,它会从数据库中读取应用程序和用户设置。

如果有更好的方法来解决这个问题,我会试一试。由于 FlowDocument 可以是 3 mb 并且所有其他属性 10K 结合起来,这对性能有很大影响,最常用的按钮是下一个对象。FlowDocument 来自 SQL 中的 varchar(max),并使用换行符和突出显示的单词进行格式化。它不仅很大 - 与其他房产相比,它也很昂贵。

FlowDocumentReader 本身似乎有一些异步支持,因为在大型文档上我快速获得第一页,然后页面以大约 100/秒的速度加载。但我仍然希望它在检索到所有其他属性后获得第 1 页。

问题正如马丁所说“由于 FlowDocument 是一个调度程序对象,它只能从创建它的线程访问”。

解决方案是序列化为 XAML 字符串。

    public string XAMLdocFlowDocument
    {
        get 
        {
            Thread.Sleep(6000);
            return XamlWriter.Save(FlowDocumentSlow); 
        } 
    }

使用转换器绑定到字符串

   <FlowDocumentReader Grid.Row="3" Grid.Column="0" VerticalAlignment="Stretch" 
        Document="{Binding Path=XAMLdocFlowDocument, IsAsync=True,
        Converter={StaticResource flowDocumentToXamlConverter}, Mode=OneWay}" />

转换器

    [ValueConversion(typeof(string), typeof(FlowDocument))]
    public class FlowDocumentToXamlConverter : IValueConverter
    {
        #region IValueConverter Members

        /// <summary>
        /// Converts from XAML markup to a WPF FlowDocument.
        /// </summary>
        public object Convert(object value, System.Type targetType,
        object parameter, System.Globalization.CultureInfo culture)
        {
            var flowDocument = new FlowDocument();
            if (value != null)
            {
                var xamlText = (string)value;
                flowDocument = (FlowDocument)XamlReader.Parse(xamlText);
            }

            // Set return value
            return flowDocument;
        }
4

1 回答 1

2

在没有看到代码的情况下,我猜测在读取属性时会创建(并加载)FlowDocument。这是在后台线程中完成的,因为属性绑定是异步的。

由于 FlowDocument 是一个调度程序对象,它只能从创建它的线程访问,在这种情况下,它是读取属性的后台线程。

因此,您的 UI 线程无法访问创建的 FlowDocument。

您需要另一种异步加载文档的方法。

也许您可以使用同步(普通)绑定并使用XamlReader.LoadAsync加载文档?我自己没有尝试过,但我猜它值得尝试。

于 2011-09-16T21:31:28.913 回答