using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Pool;
namespace XericUI.ReflectionUIGenerator
{
///
/// 字段 Entry 接口
/// 数据对象字段与 UI 组件之间的中间缓存层
///
public interface IFieldEntry
{
/// Entry 名称(字段名或编组路径)
string EntryName { get; }
/// Entry 完整路径(含父级路径)
string EntryPath { get; }
/// 主要功能标记
XuiavrgFieldTag Tag { get; }
/// 标记索引
int TagIndex { get; }
/// 排序值(越小越靠前)
int FieldOrder { get; set; }
/// 是否为编组 Entry(包含子 Entry)
bool IsGroupEntry { get; }
/// 父 Entry
IFieldEntry Parent { get; }
/// 子 Entry 列表(只读)
IReadOnlyList Children { get; }
/// 生成的 UI 实例引用
GameObject UIInstance { get; }
/// 绑定的预制体引用
GameObject BoundPrefab { get; set; }
/// 关联的 MVVM 绑定列表
IReadOnlyList Bindings { get; }
// === 生命周期 ===
/// Entry 创建时调用
void OnEntryCreate();
/// 绑定 UI 和数据时调用
void OnEntryBind();
/// 释放时调用(归还池前)
void OnEntryRelease();
/// 销毁时调用
void OnEntryDestroy();
// === 绑定管理 ===
/// 添加 MVVM 绑定到此 Entry
void AddBinding(AvrgMvvmBinding binding, AvrgMvvmScheduler scheduler);
// === UI 绑定 ===
///
/// 绑定 UI 组件
///
void BindUIComponent(GameObject uiInstance, List componentCache);
}
///
/// 字段临时 Entry 实现类
/// 作为数据对象和 UI 组件之间的中间缓存层
///
/// UI 交互事件的分配通过 XUIAvrgMDValue.BindToAccessor() 的多态机制完成,
/// 各类 XUIAvrgMDValue 子类自行管理其专属 UI 组件的交互订阅。
///
public class XuiFieldTempEntry : IFieldEntry
{
#region 对象池
private static ObjectPool _pool;
internal static ObjectPool Pool
{
get
{
if (_pool == null)
{
_pool = new ObjectPool(
createFunc: () => new XuiFieldTempEntry(),
actionOnGet: entry => entry.OnEntryCreate(),
actionOnRelease: entry => entry.OnEntryRelease(),
actionOnDestroy: entry => entry.OnEntryDestroy(),
collectionCheck: false,
defaultCapacity: 32,
maxSize: 512
);
}
return _pool;
}
}
/// 从池中获取 Entry 实例
public static XuiFieldTempEntry Get() => Pool.Get();
/// 将 Entry 归还池中
public static void Release(XuiFieldTempEntry entry) => Pool.Release(entry);
#endregion
#region 字段
private string _entryName;
private string _entryPath;
private IFieldEntry _parent;
private List _children = new List();
private List _bindings = new List();
private AvrgMvvmScheduler _scheduler;
private GameObject _uiInstance;
private GameObject _boundPrefab;
private int _fieldOrder;
private bool _uiBound;
#endregion
#region IFieldEntry 属性实现
public string EntryName => _entryName;
public string EntryPath
{
get
{
if (!string.IsNullOrEmpty(_entryPath)) return _entryPath;
if (_parent != null)
{
string parentPath = _parent.EntryPath;
return string.IsNullOrEmpty(parentPath)
? _entryName
: parentPath + "/" + _entryName;
}
return _entryName;
}
}
public XuiavrgFieldTag Tag { get; private set; }
public int TagIndex { get; private set; }
public int FieldOrder
{
get => _fieldOrder;
set => _fieldOrder = value;
}
public bool IsGroupEntry => _children.Count > 0;
public IFieldEntry Parent => _parent;
public IReadOnlyList Children => _children;
public GameObject UIInstance => _uiInstance;
public GameObject BoundPrefab
{
get => _boundPrefab;
set => _boundPrefab = value;
}
public IReadOnlyList Bindings => _bindings;
#endregion
#region 初始化方法
public void Initialize(string entryName, XuiavrgFieldTag tag = XuiavrgFieldTag.None, int tagIndex = 0)
{
_entryName = entryName;
_entryPath = null;
Tag = tag;
TagIndex = tagIndex;
_fieldOrder = 0;
_uiBound = false;
}
public void SetParent(IFieldEntry parent)
{
_parent = parent;
_entryPath = null;
}
public void AddChild(XuiFieldTempEntry child)
{
if (child == null) return;
child.SetParent(this);
_children.Add(child);
}
public void AddBinding(AvrgMvvmBinding binding, AvrgMvvmScheduler scheduler)
{
if (binding == null) return;
_bindings.Add(binding);
_scheduler = scheduler;
if (Tag == XuiavrgFieldTag.None && binding.MetaData?.Tag != XuiavrgFieldTag.None)
{
Tag = binding.MetaData.Tag;
TagIndex = binding.MetaData.TagIndex;
}
}
#endregion
#region UI 绑定
public void BindUIComponent(GameObject uiInstance, List componentCache)
{
_uiInstance = uiInstance;
if (_uiInstance == null || _uiBound) return;
if (componentCache == null)
{
componentCache = new List();
_uiInstance.GetComponentsInChildren(true, componentCache);
}
// 遍历组件缓存,寻找 XUIAvrgMDValue 按 Tag 匹配
foreach (var comp in componentCache)
{
if (comp is XUIAvrgMDValue mdValue)
{
if (mdValue.EntryTag == this.Tag &&
(this.TagIndex == 0 || mdValue.TagIndex == this.TagIndex))
{
BindComponentWithBinding(mdValue);
}
}
}
// 子 Entry 复用组件缓存
foreach (var child in _children)
{
child.BindUIComponent(_uiInstance, componentCache);
}
_uiBound = true;
}
///
/// 将 XUIAvrgMDValue 与 MVVM 绑定连接
/// 通过多态 BindToAccessor 让 UI 子类自行管理交互事件和显示更新
///
private void BindComponentWithBinding(XUIAvrgMDValue mdValue)
{
if (_bindings.Count == 0) return;
var primaryBinding = _bindings[0];
// ★ 多态调用: UI 子类自行处理交互事件和显示更新
mdValue.BindToAccessor(primaryBinding.Accessor, primaryBinding, _scheduler);
// 拆分属性子绑定处理
if (primaryBinding.SubBindings?.Count > 0 && mdValue.AvailableBindingSlots?.Count > 0)
{
var childMDValues = new List();
mdValue.GetComponentsInChildren(true, childMDValues);
foreach (var slot in mdValue.AvailableBindingSlots)
{
var subBinding = primaryBinding.SubBindings.Find(
sb => sb.MetaData?.PropertyPath == slot.propertyName);
if (subBinding == null) continue;
foreach (var childMD in childMDValues)
{
if (childMD == mdValue) continue;
if (childMD.EntryTag == slot.tag || slot.tag == XuiavrgFieldTag.None)
{
childMD.BindToAccessor(subBinding.Accessor, subBinding, _scheduler);
childMD.InitializeWithMetaData(subBinding.MetaData);
break;
}
}
}
}
// 广播主元数据到样式组件
mdValue.InitializeWithMetaData(primaryBinding.MetaData);
}
#endregion
#region 生命周期
public void OnEntryCreate()
{
_entryName = null;
_entryPath = null;
_parent = null;
_fieldOrder = 0;
_uiBound = false;
}
public void OnEntryBind()
{
foreach (var binding in _bindings)
{
var value = binding.ReadFromDataSource();
binding.NotifyUIUpdate(value, ValidationState.Normal);
if (binding.SubBindings?.Count > 0)
{
foreach (var subBinding in binding.SubBindings)
{
var subValue = subBinding.ReadFromDataSource();
subBinding.NotifyUIUpdate(subValue, ValidationState.Normal);
}
}
}
}
public void OnEntryRelease()
{
_entryName = null;
_entryPath = null;
_parent = null;
_uiInstance = null;
_boundPrefab = null;
Tag = XuiavrgFieldTag.None;
TagIndex = 0;
_fieldOrder = 0;
_uiBound = false;
foreach (var binding in _bindings)
{
binding.ClearUIEvent();
if (binding.SubBindings?.Count > 0)
{
foreach (var sub in binding.SubBindings)
sub.ClearUIEvent();
}
}
_bindings.Clear();
_scheduler = null;
foreach (var child in _children)
{
Release(child);
}
_children.Clear();
}
public void OnEntryDestroy()
{
foreach (var binding in _bindings)
{
binding.ClearUIEvent();
if (binding.SubBindings?.Count > 0)
{
foreach (var sub in binding.SubBindings)
sub.ClearUIEvent();
}
}
_bindings.Clear();
_children.Clear();
_uiInstance = null;
_scheduler = null;
}
#endregion
}
}