WPF绑定IsAsync失败

时间:2011-09-16 14:58:18

标签: wpf binding asynchronous flowdocument flowdocumentreader

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

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

生产获取更复杂,但即使使用简单的硬编码FlowDocument,IsAsyc True也会失败。

    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;
        }

1 个答案:

答案 0 :(得分:2)

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

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

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

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

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