延迟加载XAML

时间:2014-10-23 20:54:48

标签: wpf xaml silverlight

我正在研究的项目有一些相当复杂的XAML,它会显着影响视觉效果。对于初始状态,相当多的控件都被折叠了;但是,由于他们的XAML被解析并且构建了视觉/逻辑树,因此显示几乎是空白对象的速度非常慢。

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

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

这看起来像是一种合理的方法吗?任何陷阱?它似乎可以很好地测试Silverlight和WPF,虽然它不会让事情变得更快,但它让我觉得在我的特定场景中有50%的速度更快。

1 个答案:

答案 0 :(得分:6)

我遇到了同样的问题(在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;
}