using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using UnityEngine;
namespace DDD
{
public abstract class SimpleViewModel : MonoBehaviour, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public virtual void Initialize() { }
public virtual void Cleanup() { }
///
/// PropertyChanged 이벤트 발생
///
/// 변경된 속성 이름 (자동으로 설정됨)
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (string.IsNullOrEmpty(propertyName)) return;
if (_updateDepth > 0)
{
// 배치 업데이트 중: 나중에 일괄 발행
_pendingNotifications.Add(propertyName);
return;
}
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
///
/// 필드 값 변경 및 PropertyChanged 이벤트 발생
///
/// 필드 타입
/// 변경할 필드 참조
/// 새로운 값
/// 속성 이름 (자동으로 설정됨)
/// 값이 실제로 변경되었는지 여부
protected bool SetField(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
private int _updateDepth;
private readonly HashSet _pendingNotifications = new();
protected void BeginUpdate()
{
_updateDepth++;
}
protected void EndUpdate()
{
if (_updateDepth == 0)
{
Debug.LogWarning("EndUpdate called without matching BeginUpdate.");
return;
}
_updateDepth--;
// 아직 상위 배치가 진행 중이면 플러시하지 않음
if (_updateDepth > 0) return;
if (_pendingNotifications.Count > 0)
{
// 복사 후 클리어(핸들러 내부에서 BeginUpdate가 호출되어도 안전)
var toNotify = new List(_pendingNotifications);
_pendingNotifications.Clear();
foreach (var prop in toNotify)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}
}
}
}
}