【问题标题】:Deferred loading of XAML延迟加载 XAML
【发布时间】:2014-10-24 15:58:55
【问题描述】:

我正在处理的一个项目有一些相当复杂的 XAML,这些 XAML 会明显影响视觉性能。相当多的控件在初始状态下是折叠的;但是,由于他们的 XAML 已被解析并构建了可视/逻辑树,因此显示几乎是空白对象的内容非常缓慢。

看起来(并且希望在此确认)使用初始状态为 Collapsed 的 ContentControl,然后将所需控件作为该 ContentControl 的 DataTemplate 嵌入,将推迟在 DataTemplate 中加载所需控件,直到 ContentControl 被可见。

我已经构建了一个通用的 DeferredContentControl 来侦听主 UI 控件的 LayoutUpdated 事件(通常是我想要快速显示的任何元素),并且当该 UIElement 的第一个 LayoutUpdated 事件触发时,我使用Dispatcher 将 DeferredContentControl 的可见性翻转为 true,这会导致 DeferredContentControl 的 DataTemplate 中的控件实例化。当用户对屏幕的初始视图(现在很快)做出反应时,数据模板中的“加载缓慢”(但仍处于折叠状态)控件已准备就绪。

这看起来是一种合理的方法吗?有什么陷阱吗?它似乎在测试 Silverlight 和 WPF 时效果很好,虽然它不会让事情变得更快,但在我的特定场景中它给人的感觉是快了 50%。

【问题讨论】:

  • 我不会依赖 LayoutUpdated,它触发得太频繁了。
  • 对,我在第一次触发事件时断开监听器

标签: wpf xaml silverlight


【解决方案1】:

我遇到了同样的问题(在 Silverlight 项目中),并以几乎相同的方式解决了它。事实证明它按预期工作,还没有遇到任何陷阱。

当您需要控制解析 xaml 和实例化视图元素的时间点时,您始终可以使用 DataTemplates(不一定与 ContentControl 并用)。您可以调用 DataTemplate.LoadContent() 来实例化它,您不必切换 ContentControl 的可见性(尽管在内部这会导致这样的 LoadContent 调用)。

如果你想看看我的实现,它甚至可以在构建更重的 VisualTree 时显示静态文本消息:

<DeferredContent HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
    <DeferredContent.DeferredContentTemplate>
        <DataTemplate>
            <MyHeavyView/>
        </DataTemplate>
    </Controls:DeferredContent.DeferredContentTemplate>
    <TextBlock Text="Loading content..."/>
</Controls:DeferredContent>

和代码

public class DeferredContent : ContentPresenter
{
    public DataTemplate DeferredContentTemplate
    {
        get { return (DataTemplate)GetValue(DeferredContentTemplateProperty); }
        set { SetValue(DeferredContentTemplateProperty, value); }
    }

    public static readonly DependencyProperty DeferredContentTemplateProperty =
        DependencyProperty.Register("DeferredContentTemplate",
        typeof(DataTemplate), typeof(DeferredContent), null);

    public DeferredContent()
    {
        Loaded += HandleLoaded;
    }

    private void HandleLoaded(object sender, RoutedEventArgs e)
    {
        Loaded -= HandleLoaded;
        Deployment.Current.Dispatcher.BeginInvoke(ShowDeferredContent);
    }

    public void ShowDeferredContent()
    {   
        if (DeferredContentTemplate != null)
        {
            Content = DeferredContentTemplate.LoadContent();
            RaiseDeferredContentLoaded();
        }
    }

    private void RaiseDeferredContentLoaded()
    {
        var handlers = DeferredContentLoaded;
        if (handlers != null)
        {
            handlers( this, new RoutedEventArgs() );
        }
    }

    public event EventHandler<RoutedEventArgs> DeferredContentLoaded;
}

【讨论】:

  • 很好...我曾使用过 LoadContent,但有所不同,并且总是获得一个单独的实例,但我没想到为延迟模板创建 DP。我对一些附加行为也有一些问题,AssociatedObject 为空,但能够解决这些问题。在 LayoutUpdated 与 Loaded 方面,Silverlight 中 Loaded 的非确定性行为让我回避了 Loaded,但在这种情况下,这很可能无关紧要。可以仔细研究一下,以一种或另一种方式说服自己。
  • 到目前为止,我对 Loaded 事件只有积极的体验。
猜你喜欢
  • 1970-01-01
  • 2011-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-06
  • 2021-07-13
  • 2010-11-26
  • 2011-08-26
相关资源
最近更新 更多