using System; using UnityEngine.UIElements; namespace RosettaUI.UIToolkit.Builder { public static class ElementBindingExtension { // Subscribe element -> field public static void SubscribeValueOnUpdateCallOnce(this ReadOnlyValueElement element, INotifyValueChanged field) { // string以外の参照型は、elementとfieldが同じインスタンスを参照した状態の場合、 // 比較しても更新されたかわからないのでSetValueWithoutNotify()で常にfieldに値をセットする // 値に応じて何かを更新するかどうかはfield側の実装に任せる Action action = typeof(T).IsValueType switch { true => field.SetValueWithoutNotifyIfNotEqual, false when typeof(T) == typeof(string) => field.SetValueWithoutNotifyIfNotEqual, false => field.SetValueWithoutNotify }; element.GetViewBridge().SubscribeValueOnUpdateCallOnce(action); } // Subscribe field -> element private static void Subscribe(this INotifyValueChanged field, FieldBaseElement element) { field.Subscribe(element, v => v); } // Subscribe field -> element private static void Subscribe( this INotifyValueChanged field, FieldBaseElement element, Func fieldValueToElementValue) { var viewBridge = element.GetViewBridge(); field.RegisterValueChangedCallback(OnValueChanged); viewBridge.onUnsubscribe += () => field?.UnregisterValueChangedCallback(OnValueChanged); // TFieldValueがstringのとき // ラベルの更新とBaseFieldの値の更新の区別がつかないのでラベルのイベントは止めておく if (field is BaseField baseField) { baseField.labelElement.RegisterValueChangedCallback(e => e.StopPropagation()); } return; void OnValueChanged(ChangeEvent evt) { viewBridge.SetValueFromView(fieldValueToElementValue(evt.newValue)); } } // Subscribe element <-> field public static void Bind(this FieldBaseElement element, INotifyValueChanged field) { element.SubscribeValueOnUpdateCallOnce(field); field.Subscribe(element); } // Subscribe element <-(change value)-> field public static void Bind( this FieldBaseElement element, BaseField field, Func elementValueToFieldValue, Func fieldValueToElementValue ) { var viewBridge = element.GetViewBridge(); viewBridge.SubscribeValueOnUpdateCallOnce(v => field.SetValueWithoutNotifyIfNotEqual(elementValueToFieldValue(v))); field.Subscribe(element, fieldValueToElementValue); } } }