延迟加载XAML

Jim*_*eil 5 silverlight wpf xaml

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

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

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

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

Mar*_*tin 7

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

当你需要控制解析xaml的时间点并且实例化视图元素时,你总是可以使用DataTemplates(不一定在cunjuction中ContentControl).您可以调用DataTemplate.LoadContent()instatiate它,您不必切换ContentControl的可见性(虽然在内部这将导致这样的LoadContent调用).

如果需要,请查看我的实现,它甚至可以在构建较重的VisualTree时显示静态文本消息:

<DeferredContent HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
    <DeferredContent.DeferredContentTemplate>
        <DataTemplate>
            <MyHeavyView/>
        </DataTemplate>
    </Controls:DeferredContent.DeferredContentTemplate>
    <TextBlock Text="Loading content..."/>
</Controls:DeferredContent>
Run Code Online (Sandbox Code Playgroud)

和代码

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;
}
Run Code Online (Sandbox Code Playgroud)