using System; using System.Collections.Generic; using UnityEngine; namespace XericUI.ReflectionUIGenerator { /// /// MVVM 调度器 — 管理脏标记、触发 Flush 更新、检测并解决冲突 /// /// 冲突解决策略: /// - 仅数据脏 → 通知 UI 更新 /// - 仅 UI 脏 → 写入数据源(写入前校验,Invalid 驳回) /// - 双方都脏 → 走配置的冲突解决策略 /// /// 验证拦截:在 CommitToDataSource 前通过 Binding.ValidateValue() 校验。 /// Invalid 值被驳回不写入,仅通知 UI 进入无效状态。 /// public class AvrgMvvmScheduler { /// 用户可注册的外部冲突解决事件 public event Func OnConflictDetected; /// 当前配置的冲突解决策略 public ConflictResolutionStrategy DefaultStrategy { get; set; } = ConflictResolutionStrategy.PreferUI; private List _bindings = new List(); private HashSet _dirtySet = new HashSet(); private AvrgMvvmResolverConfig _resolverConfig; public AvrgMvvmScheduler(AvrgMvvmResolverConfig resolverConfig = null) { _resolverConfig = resolverConfig; } /// /// 注册绑定到调度器 /// public void Register(AvrgMvvmBinding binding) { if (!_bindings.Contains(binding)) _bindings.Add(binding); } /// /// UI 侧写入时调用 — 标记脏 /// public void MarkUIDirty(AvrgMvvmBinding binding) { binding.IsUIDirty = true; _dirtySet.Add(binding); } /// /// 数据侧写入时调用 — 标记脏 /// public void MarkDataDirty(AvrgMvvmBinding binding) { binding.IsDataDirty = true; _dirtySet.Add(binding); } /// /// 处理所有脏绑定 /// public void Flush() { if (_dirtySet.Count == 0) return; foreach (var binding in _dirtySet) { ResolveBinding(binding); binding.ClearDirty(); } _dirtySet.Clear(); } private void ResolveBinding(AvrgMvvmBinding binding) { bool uiDirty = binding.IsUIDirty; bool dataDirty = binding.IsDataDirty; if (uiDirty && dataDirty) { // 双方都脏 — 走冲突解决(内部含验证) ResolveConflict(binding); } else if (dataDirty) { // 仅数据侧更新 → 验证后通知 UI var value = binding.DataCachedValue ?? binding.ReadFromDataSource(); var state = binding.ValidateValue(value); binding.SetValidationState(state); binding.CommitToDataSource(value); binding.NotifyUIUpdate(value, state); } else if (uiDirty) { // 仅 UI 侧更新 → 验证后写入数据源 var value = binding.UICachedValue; var state = binding.ValidateValue(value); if (state == ValidationState.Invalid) { // ★ 无效值:驳回不写入,仅通知 UI 进入无效态 binding.SetValidationState(state); binding.NotifyUIUpdate(value, state); return; } binding.SetValidationState(state); binding.CommitToDataSource(value); // UI 是发起方,不再通知自身(但验证状态变更需通知) } } private void ResolveConflict(AvrgMvvmBinding binding) { // 1. 检查外部事件处理 if (OnConflictDetected != null) { try { var resolvedValue = OnConflictDetected.Invoke(binding, DefaultStrategy); if (resolvedValue != null) { var state = binding.ValidateValue(resolvedValue); binding.SetValidationState(state); binding.CommitToDataSource(resolvedValue); binding.NotifyUIUpdate(resolvedValue, state); return; } } catch (Exception e) { Debug.LogError($"[AvrgMvvmScheduler] 外部冲突解决事件异常: {e.Message}"); } } // 2. 检查 ResolverConfig 中的自定义策略 if (_resolverConfig != null && _resolverConfig.TryResolve(binding, out object configResolvedValue)) { var state = binding.ValidateValue(configResolvedValue); binding.SetValidationState(state); binding.CommitToDataSource(configResolvedValue); binding.NotifyUIUpdate(configResolvedValue, state); return; } // 3. 按默认策略解决 switch (DefaultStrategy) { case ConflictResolutionStrategy.PreferUI: { var val = binding.UICachedValue; var state = binding.ValidateValue(val); if (state == ValidationState.Invalid) { binding.SetValidationState(state); binding.NotifyUIUpdate(val, state); return; } binding.SetValidationState(state); binding.CommitToDataSource(val); binding.NotifyUIUpdate(val, state); break; } case ConflictResolutionStrategy.PreferData: { var dataValue = binding.DataCachedValue ?? binding.ReadFromDataSource(); var state = binding.ValidateValue(dataValue); binding.SetValidationState(state); binding.CommitToDataSource(dataValue); binding.NotifyUIUpdate(dataValue, state); break; } case ConflictResolutionStrategy.CompareValues: { object uiVal = binding.UICachedValue; object dataVal = binding.DataCachedValue ?? binding.ReadFromDataSource(); if (Equals(uiVal, dataVal)) { // 值相同,忽略冲突 var state2 = binding.ValidateValue(dataVal); binding.SetValidationState(state2); binding.NotifyUIUpdate(dataVal, state2); break; } // 值不同,回退到 PreferUI var val = binding.UICachedValue; var state = binding.ValidateValue(val); if (state == ValidationState.Invalid) { binding.SetValidationState(state); binding.NotifyUIUpdate(val, state); return; } binding.SetValidationState(state); binding.CommitToDataSource(val); binding.NotifyUIUpdate(val, state); Debug.LogWarning($"[AvrgMvvmScheduler] 值冲突(CompareValues回退PreferUI): {binding.MetaData?.MemberName}"); break; } default: { var val = binding.UICachedValue; var state = binding.ValidateValue(val); binding.SetValidationState(state); binding.CommitToDataSource(val); binding.NotifyUIUpdate(val, state); break; } } } /// /// 清空所有注册 /// public void Clear() { _bindings.Clear(); _dirtySet.Clear(); } /// /// 手动将绑定的 UI 值标记为脏 /// public void MarkUI(AvrgMvvmBinding binding, object value) { binding.WriteFromUI(value); MarkUIDirty(binding); } /// /// 手动将绑定的数据值写入并标记脏 /// public void MarkData(AvrgMvvmBinding binding, object value) { binding.WriteFromData(value); MarkDataDirty(binding); } } /// /// 冲突解决策略枚举 /// public enum ConflictResolutionStrategy { /// 优先使用 UI 侧的值 PreferUI, /// 优先使用数据源侧的值 PreferData, /// 比较两者,相同则忽略,不同则优先 UI CompareValues, } }