ProjectDDD/Assets/_DDD/_Scripts/GameUi/Utils/Binding/BindingContext.cs

170 lines
5.4 KiB
C#
Raw Normal View History

2025-08-20 06:22:08 +00:00
using System;
using System.Collections.Generic;
using System.ComponentModel;
2025-08-24 20:12:05 +00:00
using System.Linq.Expressions;
2025-08-20 06:22:08 +00:00
using System.Reflection;
2025-08-21 07:25:27 +00:00
namespace DDD
2025-08-20 06:22:08 +00:00
{
/// <summary>
/// 바인딩 컨텍스트 - ViewModel과 View 간의 데이터 바인딩을 관리
/// </summary>
public class BindingContext
{
private readonly Dictionary<string, List<IBindingTarget>> _bindings = new();
private readonly Dictionary<string, IValueConverter> _converters = new();
private INotifyPropertyChanged _dataContext;
2025-08-24 20:12:05 +00:00
public void Bind<TVm, TProp>(Expression<Func<TVm, TProp>> property, IBindingTarget target, IValueConverter converter = null)
{
var path = BindingPath.For(property);
Bind(path, target, converter);
}
2025-08-20 06:22:08 +00:00
/// <summary>
/// 데이터 컨텍스트 (ViewModel) 설정
/// </summary>
/// <param name="dataContext">바인딩할 ViewModel</param>
public void SetDataContext(INotifyPropertyChanged dataContext)
{
if (_dataContext != null)
_dataContext.PropertyChanged -= OnPropertyChanged;
_dataContext = dataContext;
if (_dataContext != null)
{
_dataContext.PropertyChanged += OnPropertyChanged;
RefreshAllBindings();
}
}
/// <summary>
/// 속성 바인딩 추가
/// </summary>
/// <param name="propertyPath">바인딩할 속성 경로</param>
/// <param name="target">바인딩 타겟</param>
/// <param name="converter">값 변환기 (선택사항)</param>
public void Bind(string propertyPath, IBindingTarget target, IValueConverter converter = null)
{
if (!_bindings.ContainsKey(propertyPath))
_bindings[propertyPath] = new List<IBindingTarget>();
_bindings[propertyPath].Add(target);
if (converter != null)
_converters[propertyPath] = converter;
// 즉시 초기값 설정
UpdateBinding(propertyPath);
}
/// <summary>
/// 속성 변경 이벤트 핸들러
/// </summary>
private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
UpdateBinding(e.PropertyName);
2025-08-24 20:12:05 +00:00
var prefix = e.PropertyName + ".";
foreach (var key in _bindings.Keys)
{
if (key.StartsWith(prefix, StringComparison.Ordinal))
{
UpdateBinding(key);
}
}
2025-08-20 06:22:08 +00:00
}
/// <summary>
/// 특정 속성의 바인딩 업데이트
/// </summary>
/// <param name="propertyPath">업데이트할 속성 경로</param>
private void UpdateBinding(string propertyPath)
{
if (!_bindings.ContainsKey(propertyPath)) return;
var value = GetPropertyValue(propertyPath);
// 컨버터 적용
if (_converters.TryGetValue(propertyPath, out var converter))
value = converter.Convert(value);
foreach (var target in _bindings[propertyPath])
{
target.UpdateValue(value);
}
}
/// <summary>
/// 속성 값 가져오기 (리플렉션 사용)
/// </summary>
/// <param name="propertyPath">속성 경로</param>
/// <returns>속성 값</returns>
private object GetPropertyValue(string propertyPath)
{
if (_dataContext == null) return null;
// 중첩 속성 지원 (예: "ItemData.Name")
var properties = propertyPath.Split('.');
object current = _dataContext;
foreach (var prop in properties)
{
if (current == null) return null;
var property = current.GetType().GetProperty(prop);
current = property?.GetValue(current);
}
return current;
}
/// <summary>
/// 모든 바인딩 새로고침
/// </summary>
private void RefreshAllBindings()
{
foreach (var propertyPath in _bindings.Keys)
{
UpdateBinding(propertyPath);
}
}
/// <summary>
/// 리소스 정리
/// </summary>
public void Dispose()
{
if (_dataContext != null)
_dataContext.PropertyChanged -= OnPropertyChanged;
_bindings.Clear();
_converters.Clear();
}
}
/// <summary>
/// 속성 경로 캐시 - 성능 최적화를 위한 리플렉션 결과 캐싱
/// </summary>
public static class PropertyPathCache
{
private static readonly Dictionary<Type, Dictionary<string, PropertyInfo>> _cache = new();
/// <summary>
/// 캐시된 PropertyInfo 가져오기
/// </summary>
/// <param name="type">타입</param>
/// <param name="propertyName">속성 이름</param>
/// <returns>PropertyInfo</returns>
public static PropertyInfo GetProperty(Type type, string propertyName)
{
if (!_cache.ContainsKey(type))
_cache[type] = new Dictionary<string, PropertyInfo>();
if (!_cache[type].ContainsKey(propertyName))
_cache[type][propertyName] = type.GetProperty(propertyName);
return _cache[type][propertyName];
}
}
}