Version: 1.6
语言 : 中文
定义记录级别
运行时数据绑定示例

创建自定义绑定类型

您可以创建自定义绑定类型来扩展运行时绑定系统。若要创建自定义绑定类型,请创建一个类并从 CustomBinding 类继承它。

注册并取消绑定对象

CustomBinding 就像 ibinding 接口一样,它允许您注册多个绑定实例,而不是单个绑定实例。这 CustomBinding 是一个可扩展的入口点,仅提供 Update 更新绑定的方法。但是,您可以在注册,未注册,以及数据源上下文对元素上更改时,可以实现以下方法以接收回调:

定义数据源和数据源路径

要定义绑定类型的数据源和数据源路径,请实现idatasourceProvider界面。绑定系统使用 dataSourcedataSourcePath 接口提供的属性以确定已解决的数据源和数据源路径。这些属性被称为 “local” ,因为它们覆盖了从层次结构获得的值。重要的是,修改这些 “local” 属性不会影响元素本身或其任何后代。

定义更新触发器

默认情况下,绑定系统更新CustomBinding实例在每个帧。

要定义更新触发器,请使用以下方法:

  • Markdirty:将绑定对象设置为 Dirty 使其在下一个周期中进行更新。
  • updateTrigger:使用此enum属性以更改绑定的更新方式。
  • bindingResult:使用此方法自定义更新过程。这bindingResult是一个告诉您更新是否成功的结构。它包含一个statusmessage

bindingResult包含statusmessage。以下是可能的值status

  • Success :绑定更新成功。如果绑定实例不需要恒定更新,则直到数据源发生更改或根据更新触发器明确标记为脏物,它才会再次更新。
  • Failure :绑定更新不成功。如果绑定实例不需要恒定更新,则直到数据源发生更改或根据更新触发器明确标记为脏物,它才会再次更新。
  • Pending :绑定更新仍在进行中。该系统会自动将绑定实例标记为肮脏,直到它获得成功或失败响应为止。

您可以使用 Pending 结果 BindingResult 如果需要在下一个周期更新绑定对象,则通知绑定系统的方法。

例子

本节提供了一个示例,以演示如何创建自定义绑定类型并在 UI 构建器,UXML和C#中设置绑定。

以下示例创建了显示当前时间的自定义绑定类型。您可以将其绑定到text标签的属性以创建时钟。

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()
        };
    }
}

当您创建自定义绑定类型时,它会出现在 Add Binding UI构建器中的窗口。为了在UI构建器中设置绑定,Add Binding 窗口,选择 CurrentTimeBinding 来自 Type 列表。

该结合的UXML等效如下:

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

该绑定的c#等效如下:

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

最佳实践

遵循以下技巧和最佳实践来优化性能:

  • 最小化每元素状态使用 :减少自定义绑定类型中对每一元素状态的依赖。取而代之的是,尽可能利用共享或全球状态来提高性能并简化维护。
  • 使用 BindingUpdateTrigger.OnSourceChanged:当您的绑定类型仅在源中检测到更改时需要更新时,请设置updateTriggerBindingUpdateTrigger.OnSourceChanged。这样可以确保仅在必要时才更新绑定类型,从而优化性能。
  • 使用 BindingUpdateTrigger.WhenDirty 用于手动更新:如果您手动更新绑定类型,并且不需要立即同步,请设置updateTriggerBindingUpdateTrigger.WhenDirty。这使您可以手动控制绑定类型更新何时,从而提供灵活性和控制同步。
  • 利用回调 :尽可能使用OnActivated,,,,OnDeactivated, 或者OnDataSourceChanged回调而不是Update回调。这些回调是在特定的生命周期事件上触发的,降低了不必要的更新并提高了效率。通过使用适当的回调,您可以优化绑定类型的行为,并确保在需要时确切地进行更新。

其他资源

定义记录级别
运行时数据绑定示例