x:Load 属性

可以使用 x:Load 优化 XAML 应用的启动、可视化树创建和内存使用情况。 使用 x:Load 具有与 Visibility 类似的视觉效果,不同之处在于,如果未加载元素,则会释放其内存,并在内部使用小占位符标记其在可视化树中的位置。

可以通过代码或使用 x:Bind 表达式加载和卸载具有 x:Load 的 UI 元素。 这可用于降低不经常或有条件地显示的元素的成本。 在 Grid 或 StackPanel 等容器上使用 x:Load 时,容器及其所有子级都会作为组加载或卸载。

XAML 框架对延迟元素的跟踪会将大约 600 字节添加到使用了 x:Load 属性的每个元素的内存使用情况,用于处理占位符的内存。 因此,过度使用此属性可能会导致性能实际降低。 建议仅在需要隐藏的元素上使用它。 如果在容器上使用 x:Load,则仅对具有 x:Load 属性的元素支付开销。

重要

从 Windows 10 版本 1703(创意者更新)开始,可以使用 x:Load 属性。 Visual Studio 项目面向的最小版本必须是 Windows 10 创意者更新(10.0 版本 15063), 才能使用 x:Load。

XAML 属性用法

<object x:Load="True" .../>
<object x:Load="False" .../>
<object x:Load="{x:Bind Path.to.a.boolean, Mode=OneWay}" .../>

加载元素

可通过多种不同的方法来加载元素:

  • 使用 x:Bind 表达式指定加载状态。 表达式应返回 true 以加载并 返回 false 以卸载元素。
  • 使用在元素上定义的名称调用 FindName
  • 请使用在元素上定义的名称来调用GetTemplateChild
  • VisualState 中,使用面向 x:Load 元素的 SetterStoryboard 动画。
  • 将任何Storyboard中未加载的元素作为目标。

注释

元素实例化后,它会在 UI 线程上创建,因此,如果在一次创建过多内容,则可能会导致 UI 停滞不前。

以前面列出的任意方式创建延迟元素后,会发生以下几件事:

  • 引发元素上的 Loaded 事件。
  • x:Name 字段已设置。
  • 元素上的任何 x:Bind 绑定都会被应用。
  • 如果您已注册接收与包含延迟元素的属性相关的属性更改通知,则会触发通知。

卸载元素

卸载元素:

  • 使用 x:Bind 表达式指定加载状态。 表达式应返回 true 以加载并 返回 false 以卸载元素。
  • 在 Page 或 UserControl 中,调用 UnloadObject 并传入对象引用
  • 调用 Microsoft.UI.Xaml.Markup.XamlMarkupHelper.UnloadObject 并传入对象引用

当一个对象被卸载时,它将在树中被一个占位符替代。 在释放所有引用之前,对象实例将保留在内存中。 Page/UserControl 上的 UnloadObject API 旨在释放 codegen 为 x:Name 和 x:Bind 保留的引用。 如果在应用代码中保存其他引用,则还需要释放这些引用。

卸载某个元素时,将丢弃与该元素关联的所有状态,因此,如果将 x:Load 用作可见性的优化版本,则确保通过绑定应用所有状态,或者在触发加载事件时通过代码重新应用所有状态。

Restrictions

使用 x:Load 的限制如下:

  • 因为以后需要查找该元素,必须为该元素定义一个x:Name
  • 只能在派生自 UIElementFlyoutBase 的类型上使用 x:Load。
  • 不能对 PageUserControlDataTemplate 中的根元素使用 x:Load。
  • 不能对 ResourceDictionary 中的元素使用 x:Load。
  • 不能在随 XamlReader.Load 一起加载的松散 XAML 上使用 x:Load。
  • 移动父元素将清除尚未加载的任何元素。

注解

可以在嵌套元素上使用 x:Load,但必须从最外层元素开始被实现。  如果在实现父元素之前尝试实现子元素,则会引发异常。

通常,我们建议延迟在第一帧中不可查看的元素。 寻找可推迟候选项的一个有效准则是查找正在使用折叠可见性创建的元素。 此外,由用户交互触发的 UI 是查找可以延迟的元素的好位置。

请谨慎地推迟 ListView 中的元素,因为它会减少启动时间,但也可能会根据所创建的内容降低平移性能。 如果要提高平移性能,请参阅 {x:Bind} 标记扩展x:Phase 属性 文档。

如果 x:Phase 属性x:Load 结合使用,则在实现元素或元素树时,绑定将应用到当前阶段并包括当前阶段。 为 x:Phase 指定的阶段会影响或控制元素的加载状态。 当列表项作为平移的一部分回收时,实现的元素的行为方式与其他活动元素相同,并且编译的绑定({x:Bind} 绑定)使用相同的规则进行处理,包括分段。

一般准则是衡量应用前后的性能,以确保获得所需的性能。

为了最大程度地减少向元素添加 x:Load 时的行为变更(除性能外),x:Bind 绑定在正常的时机进行计算,就像没有元素使用 x:Load 一样。 例如,当根元素加载时,将计算 OneTime x:Bind 绑定。 如果在计算 x:Bind 绑定时未实现该元素,则在加载该元素时,将保存计算值并将其应用于该元素。 如果您预期 x:Bind 绑定在元素实例化时被计算,那么这种行为可能会令人感到意外。

Example

<StackPanel>
    <Grid x:Name="DeferredGrid" x:Load="False">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>

        <Rectangle Height="100" Width="100" Fill="Orange" Margin="0,0,4,4"/>
        <Rectangle Height="100" Width="100" Fill="Green" Grid.Column="1" Margin="4,0,0,4"/>
        <Rectangle Height="100" Width="100" Fill="Blue" Grid.Row="1" Margin="0,4,4,0"/>
        <Rectangle Height="100" Width="100" Fill="Gold" Grid.Row="1" Grid.Column="1" Margin="4,4,0,0"
                   x:Name="one" x:Load="{x:Bind (x:Boolean)CheckBox1.IsChecked, Mode=OneWay}"/>
        <Rectangle Height="100" Width="100" Fill="Silver" Grid.Row="1" Grid.Column="1" Margin="4,4,0,0"
                   x:Name="two" x:Load="{x:Bind Not(CheckBox1.IsChecked), Mode=OneWay}"/>
    </Grid>

    <Button Content="Load elements" Click="LoadElements_Click"/>
    <Button Content="Unload elements" Click="UnloadElements_Click"/>
    <CheckBox x:Name="CheckBox1" Content="Swap Elements" />
</StackPanel>
// This is used by the bindings between the rectangles and check box.
private bool Not(bool? value) { return !(value==true); }

private void LoadElements_Click(object sender, RoutedEventArgs e)
{
    // This will load the deferred grid, but not the nested
    // rectangles that have x:Load attributes.
    this.FindName("DeferredGrid"); 
}

private void UnloadElements_Click(object sender, RoutedEventArgs e)
{
     // This will unload the grid and all its child elements.
     this.UnloadObject(DeferredGrid);
}