using System; using System.Collections.Generic; using System.Linq; using RosettaUI.Reactive; namespace RosettaUI { /// /// 動的に内容が変化するElement /// UI実装側はbuildの結果をいれるプレースホルダー的な役割 /// public class DynamicElement : ElementGroup { #region Static public static DynamicElement Create(Func readStatus, Func buildWithStatus, string displayName = null) { var status = readStatus(); return new DynamicElement( () => buildWithStatus(status), e => { var newStatus = readStatus(); var rebuild = !EqualityComparer.Default.Equals(newStatus, status); if (rebuild) status = newStatus; return rebuild; }, displayName ); } #endregion public event Action onBuildChildren; private event Action bindChildrenToView; private readonly Func _build; private readonly string _displayName; private readonly Func _rebuildIf; private readonly BinderHistory.Snapshot _binderTypeHistorySnapshot; public DynamicElement(Func build, Func rebuildIf, string displayName = null) { _build = build; _rebuildIf = rebuildIf; _displayName = displayName; _binderTypeHistorySnapshot = BinderHistory.Snapshot.Create(); BuildElement(); enableRx.Subscribe(enable => { if (enable) { CheckAndRebuild(); } }); } public override string DisplayName => string.IsNullOrEmpty(_displayName) ? base.DisplayName : _displayName; protected override void UpdateInternal() { CheckAndRebuild(); base.UpdateInternal(); } private void BuildElement() { while (Children.Any()) { var child = Children.Last(); RemoveChild(child, false); } using var applyScope = _binderTypeHistorySnapshot.GetApplyScope(); SetElements(new[] {_build?.Invoke()}); bindChildrenToView?.Invoke(this); onBuildChildren?.Invoke(this); } public void CheckAndRebuild() { if (!(_rebuildIf?.Invoke(this) ?? false)) return; BuildElement(); } private void ClearBindView() => bindChildrenToView = null; protected override ElementViewBridge CreateViewBridge() => new DynamicElementViewBridge(this); public class DynamicElementViewBridge : ElementViewBridge { private DynamicElement Element => (DynamicElement)element; public DynamicElementViewBridge(DynamicElement element) : base(element) { } public void RegisterBindViewAndCallOnce(Action action) { Element.bindChildrenToView += action; action?.Invoke(Element); } public override void UnsubscribeAll() { base.UnsubscribeAll(); Element.ClearBindView(); } } } public static partial class ElementViewBridgeExtensions { public static DynamicElement.DynamicElementViewBridge GetViewBridge(this DynamicElement element) => (DynamicElement.DynamicElementViewBridge)element.ViewBridge; } }