Unity 6.3
0 онлайн 25 гостей 3 в системе
Вход

Создание настраиваемых типов привязок

Систему привязок времени выполнения можно расширить собственными типами привязок. Чтобы создать такой тип, объявите класс и унаследуйте его от CustomBinding class.

Регистрация и отмена регистрации объектов привязки

CustomBinding это как IBinding интерфейс, позволяющий зарегистрировать не одну, а сразу несколько привязок. CustomBinding является входной точкой расширяемости и обеспечивает только Update метод для обновления привязки. Однако можно реализовать следующие методы для получения обратного вызова при регистрации или отмене регистрации привязки, а также при изменении контекста источника данных для элемента:

Важно: OnDataSourceChanged вызывается при изменении самого свойства dataSource (когда элементу назначается новый объект источника данных), а не при изменении данных в источнике. Это отличается от BindingUpdateTrigger.OnSourceChanged, которое реагирует на изменения в исходных данных. Если вам нужно реагировать на изменения в исходных данных, используйте соответствующие триггеры обновления или внедрите отслеживание изменений в источнике данных.

Определение источника данных и пути к нему

Чтобы определить источник данных и путь к источнику данных для типа привязки, реализуйте IDataSourceProvider интерфейс. Система привязок использует dataSource и dataSourcePath свойства, предоставляемые этим интерфейсом, чтобы определить разрешённый источник данных и путь к нему. Их называют «локальными», поскольку они переопределяют значения, полученные из иерархии. Важно, что изменение этих «локальных» свойств не затрагивает ни сам элемент, ни его потомков.

Определение триггеров обновления

По умолчанию система привязки обновляет экземпляр CustomBinding в каждом кадре.

Чтобы определить триггеры обновления, используйте следующие методы:

  • MarkDirty: Устанавливает объект привязки в качестве dirty, чтобы он обновлялся во время следующего цикла.
  • updateTrigger: Используйте это свойство enum для изменения способа обновления привязки.
  • BindingResult: Используйте этот метод для настройки процесса обновления. BindingResult — это структура, сообщающая, успешно ли прошло обновление. Она содержит status и a message.

BindingResult содержит status и message. Ниже приводятся возможные значения status:

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

Вы можете использовать результат Pending метода BindingResult для информирования системы привязки о том, что объект привязки должен быть обновлен в следующем цикле.

Пример

В этом разделе приведен пример, демонстрирующий создание настраиваемого типа привязки и настройку привязки в UI Builder, UXML и C#.

В следующем примере создается пользовательский тип привязки, отображающий текущее время. Вы можете привязать его к свойству text метки Label, чтобы создать часы.

using System;
using Unity.Properties;
using UnityEngine.UIElements;

[UxmlObject]
public partial class CurrentTimeBinding : CustomBinding
{
    [UxmlAttribute]
    public string timeFormat = "HH:mm:ss";

    public CurrentTimeBinding()
    {
        updateTrigger = BindingUpdateTrigger.EveryUpdate;
    }

    protected override BindingResult Update(in BindingContext context)
    {
        var timeNow = DateTime.Now.ToString(timeFormat);
        var element = context.targetElement;
        if (ConverterGroups.TrySetValueGlobal(ref element, context.bindingId, timeNow, out var errorCode))
            return new BindingResult(BindingStatus.Success);

        // Error handling
        var bindingTypename = TypeUtility.GetTypeDisplayName(typeof(CurrentTimeBinding));
        var bindingId = $"{TypeUtility.GetTypeDisplayName(element.GetType())}.{context.bindingId}";

        return errorCode switch
        {
            VisitReturnCode.InvalidPath => new BindingResult(BindingStatus.Failure, $"{bindingTypename}: Binding id `{bindingId}` is either invalid or contains a `null` value."),
            VisitReturnCode.InvalidCast => new BindingResult(BindingStatus.Failure, $"{bindingTypename}: Invalid conversion from `string` for binding id `{bindingId}`"),
            VisitReturnCode.AccessViolation => new BindingResult(BindingStatus.Failure, $"{bindingTypename}: Trying set value for binding id `{bindingId}`, but it is read-only."),
            _ => throw new ArgumentOutOfRangeException()
        };
    }
}

При создании настраиваемого типа привязки он появляется в окне Добавление привязки в UI Builder. Чтобы настроить привязку в UI Builder, в окне Добавление привязки выберите CurrentTimeBinding из списка Тип.

Эквивалент UXML этой связи выглядит следующим образом:

 <ui:Label text="Label">
    <Bindings>
        <CurrentTimeBinding property="text" />
    </Bindings>
</ui:Label>

Эквивалент C# этой связи выглядит следующим образом:

var label = new Label();
label.SetBinding("text",  new CurrentTimeBinding());

Передовая практика

Для оптимизации производительности следуйте этим советам и рекомендациям:

  • Минимизация состояния, хранимого на каждый элемент: сократите зависимость от состояния, привязанного к отдельному элементу, в своих типах пользовательских привязок. Там, где возможно, используйте общее или глобальное состояние — это повысит производительность и упростит сопровождение.
  • Используйте BindingUpdateTrigger.OnSourceChanged: Если тип привязки требует обновления только при обнаружении изменений в исходном коде, установите updateTrigger на BindingUpdateTrigger.OnSourceChanged. Это гарантирует, что тип привязки обновляется только при необходимости, оптимизируя производительность.
  • Используйте BindingUpdateTrigger.WhenDirty для ручных обновлений: Если вы обновляете тип привязки вручную и не требуете немедленной синхронизации, установите updateTrigger на BindingUpdateTrigger.WhenDirty. Это позволяет вручную управлять обновлением типа привязки, обеспечивая гибкость и контроль над синхронизацией.
  • Использование обратных вызовов: По мере возможности используйте обратные вызовы OnActivated, OnDeactivatedили OnDataSourceChanged вместо обратного вызова Update. Эти обратные вызовы запускаются при определенных событиях жизненного цикла, уменьшая количество ненужных обновлений и повышая эффективность. Используя соответствующий обратный вызов, вы можете оптимизировать поведение типа привязки и обеспечить обновление точно тогда, когда это необходимо.

Дополнительные ресурсы