【问题标题】:WPF Binding IsAsync FailWPF 绑定 IsAsync 失败
【发布时间】:2011-09-16 14:58:17
【问题描述】:

拥有一个大多数属性都非常轻量级的对象 - 最多 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;
        }

【问题讨论】:

  • 这种情况下的 FallbackValue 是什么?是否需要在绑定中指定(因为这可能会在异步操作处理时应用?)
  • 仍然失败并返回 FallbackValue。如果我执行 PriorityBinding,它将通过非异步,甚至调用异步 get,但随后在 XMAL 中失败。
  • 为什么投反对票?什么不清楚、缺乏研究或没有用处?
  • 再次感谢 Marten。我最近升级了代码以使用 BackgroundWorker 而不是 IsAsync=True 并获得了 10 倍的性能提升。如果您有一个返回少量文本的昂贵进程,否则 IsAsync=True 非常好,否则直接使用 BackgroundWorker 或线程。 Dispatcher 很复杂,但它的存在是有充分理由的。

标签: wpf binding asynchronous flowdocument flowdocumentreader


【解决方案1】:

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

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

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

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

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

【讨论】:

  • 我在问题中添加了get。有趣的是,它调用 get 并且 get 返回流文档而没有错误。当 UI 尝试绑定时,它会失败。似乎 get 调用应该在正确的 UI 线程上。根据文档,您需要做的就是添加 IsAsync = True ,它将常规 get 转换为异步调用。我会看看你的建议,但说实话我并不完全理解。
  • get 调用是异步完成的(在另一个线程上)。问题是您在 get 方法中创建了一个新的 FlowDocument 实例。即使该实例被正确返回,它也不能被您的 UI 线程使用,因为它是由另一个线程(发出 get 调用的线程)创建的。这就是为什么在 UI 尝试“使用”返回的 FlowDocument 实例之前不会发生错误的原因。
  • 您需要在 UI 线程上创建 FlowDocument 实例。那么问题是你应该如何异步加载它。
  • 我想我同意,但我不知道怎么做。根据应该为我照顾的文件。我什至看到非 Microsoft 代码示例表明它们可以工作。我认为问题出在静态源中,可能是一个错误。我仍然给你 +1。
  • @BalamBalam:您目前如何将内容加载到 FlowDocument 中?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-18
  • 2018-01-21
  • 1970-01-01
  • 1970-01-01
  • 2015-01-23
相关资源
最近更新 更多