Поделиться через


Атрибут x:Load

Вы можете использовать x:Load для оптимизации запуска, создания визуального дерева и использования памяти приложения XAML. Использование x:Load имеет аналогичный визуальный эффект как видимость, за исключением того, что когда элемент не загружается, его память освобождается, и внутренне используется небольшой заполнитель для пометки его места в визуальном дереве.

Элемент пользовательского интерфейса, атрибут x:Load, можно загрузить и выгрузить с помощью кода или с помощью выражения x:Bind . Это полезно для уменьшения затрат на элементы, которые отображаются редко или условно. При использовании x:Load в контейнере, например Grid или StackPanel, контейнер и все его дочерние элементы загружаются или выгружаются в виде группы.

Отслеживание отложенных элементов платформой XAML добавляет около 600 байт к использованию памяти для каждого элемента с атрибутом x:Load, чтобы учесть заполнителя. Таким образом, можно перепользовать этот атрибут в той степени, в которой производительность на самом деле уменьшается. Рекомендуется использовать его только для элементов, которые должны быть скрыты. Если вы используете x:Load в контейнере, то затраты оплачиваются только для элемента с атрибутом x:Load.

Это важно

Атрибут x:Load доступен начиная с Windows 10 версии 1703 (Creators Update). Минимальная версия, предназначенная для проекта Visual Studio, должна быть Windows 10 Creators Update (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 используйте анимацию Setter или Storyboard , предназначенную для элемента x:Load.
  • Нацелим на выгруженный элемент в любой раскадровки.

Замечание

После начала инстанцирования элемента его создание выполняется в потоке пользовательского интерфейса, поэтому пользовательский интерфейс может тормозить, если слишком много элементов создается одновременно.

После создания отложенного элемента в любом из перечисленных ранее способов происходит несколько действий.

  • Вызывается событие Loaded в элементе.
  • Поле для x:Name задано.
  • Привязки x:Bind, применённые к элементу, активируются.
  • Если вы зарегистрировались для получения уведомлений об изменении свойств в отношении объекта, содержащего отложенные элементы, уведомление отправляется.

Выгрузка элементов

Чтобы выгрузить элемент:

  • Используйте выражение x:Bind, чтобы указать состояние загрузки. Выражение должно возвращать true для загрузки и false для выгрузки элемента.
  • На странице или в UserControl вызовите UnloadObject и передайте ссылку на объект
  • Вызовите Microsoft.UI.Xaml.Markup.XamlMarkupHelper.UnloadObject и передайте ссылку на объект

Когда объект выгружается, он будет заменен в дереве заполнителем. Экземпляр объекта останется в памяти до тех пор, пока не будут выпущены все ссылки. API UnloadObject на странице/UserControl предназначен для освобождения ссылок, удерживаемых кодегеном для x:Name и x:Bind. Если вы храните дополнительные ссылки в коде приложения, они также должны быть выпущены.

При выгрузке элемента все состояние, связанное с элементом, будет удалено, поэтому при использовании x:Load в качестве оптимизированной версии свойства Visibility убедитесь, что всё состояние применяется через привязки или повторно применяется кодом при срабатывании события Loaded.

Restrictions

Ограничения для использования x:Load :

  • Необходимо определить x:Name для элемента, так как его необходимо найти позже.
  • Вы можете использовать только типы x:Load, производные от UIElement или FlyoutBase.
  • Нельзя использовать x:Load для корневых элементов в Page, UserControl или DataTemplate.
  • Нельзя использовать x:Load для элементов в ResourceDictionary.
  • Нельзя использовать x:Load на свободном языке XAML, загруженном с помощью XamlReader.Load.
  • Перемещение родительского элемента очищает все элементы, которые не были загружены.

Замечания

Вы можете использовать x:Load для вложенных элементов, однако их необходимо осуществлять, начиная с внешнего элемента и двигаясь внутрь.  Если вы пытаетесь реализовать дочерний элемент до того, как был реализован родительский элемент, возникает исключение.

Как правило, рекомендуется отложить элементы, которые недоступны для просмотра в первом кадре. Хорошее правило для отбора кандидатов, которые должны быть отложены, заключается в поиске элементов, создаваемых с "свернутой" видимостью. Кроме того, пользовательский интерфейс, активируемый взаимодействием с пользователем, является хорошим местом для поиска элементов, которые можно отложить.

Будьте осторожны с отсрочкой элементов в 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);
}