-
-
Save scho/d737ec33aa3b5b1e7fc8e04990d866d2 to your computer and use it in GitHub Desktop.
Minimalistic MVVM for Unity, UI Toolkit and UniRX
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using UnityEngine.UIElements; | |
namespace ProjectHive.UI.UI | |
{ | |
public interface IView<in TViewModel> : IView | |
{ | |
IDisposable Bind(TViewModel viewModel); | |
} | |
public interface IView : IDisposable | |
{ | |
VisualElement TemplateRoot { get; set; } | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Reflection; | |
using UnityEngine.UIElements; | |
namespace ProjectHive.UI.UI | |
{ | |
[AttributeUsage(AttributeTargets.Field)] | |
public class QueryAttribute : Attribute | |
{ | |
public string Q { get; } | |
public QueryAttribute(string q) | |
{ | |
Q = q; | |
} | |
} | |
public static class QueryAttributeExtensions | |
{ | |
private static readonly IDictionary<Type, IList<Tuple<FieldInfo, QueryAttribute>>> TypeCache = | |
new Dictionary<Type, IList<Tuple<FieldInfo, QueryAttribute>>>(); | |
public static void ResolveQueryAttributes<T>(this T view) where T : IView | |
{ | |
var viewType = typeof(T); | |
if (!TypeCache.ContainsKey(viewType)) | |
{ | |
var result = new List<Tuple<FieldInfo, QueryAttribute>>(); | |
var fieldInfos = viewType.Assembly.GetTypes() | |
.Where(type => type.IsClass) | |
.Where(type => type.IsAssignableFrom(viewType)) | |
.SelectMany(type => type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic)); | |
foreach (var fieldInfo in fieldInfos) | |
{ | |
var attribute = (QueryAttribute) fieldInfo.GetCustomAttributes(false) | |
.FirstOrDefault(attribute => attribute is QueryAttribute); | |
if (attribute != null) | |
{ | |
result.Add(Tuple.Create(fieldInfo, attribute)); | |
} | |
} | |
TypeCache.Add(viewType, result); | |
} | |
var fields = TypeCache[viewType]; | |
for (var i = 0; i < fields.Count; i++) | |
{ | |
var (fieldInfo, attribute) = fields[i]; | |
var qParts = attribute.Q.Split('.'); | |
var visualElement = view.TemplateRoot; | |
for (var iQPart = 0; iQPart < qParts.Length; iQPart++) | |
{ | |
var qPart = qParts[iQPart]; | |
if (iQPart < qParts.Length - 1 || fieldInfo.FieldType == typeof(VisualElement)) | |
{ | |
visualElement = visualElement.Q(qPart); | |
} | |
else | |
{ | |
visualElement = visualElement.Query() | |
.Where(e => e.GetType() == fieldInfo.FieldType && qPart.Equals(e.name)) | |
.Build() | |
.First(); | |
} | |
} | |
fieldInfo.SetValue(view, visualElement); | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using JetBrains.Annotations; | |
using UniRx; | |
using UnityEngine.UIElements; | |
namespace ProjectHive.UI.UI | |
{ | |
public abstract class View<T> : IView<T> | |
{ | |
private VisualElement _templateRoot; | |
public VisualElement TemplateRoot | |
{ | |
get => _templateRoot; | |
set | |
{ | |
_templateRoot = value; | |
Initialize(); | |
} | |
} | |
private CompositeDisposable _disposables; | |
public CompositeDisposable Disposables => _disposables ??= new CompositeDisposable(); | |
protected abstract void Initialize(); | |
[MustUseReturnValue] | |
public abstract IDisposable Bind(T viewModel); | |
public void Dispose() | |
{ | |
_disposables?.Dispose(); | |
_disposables = null; | |
} | |
} | |
public static class ViewExtensions | |
{ | |
public static T AddTo<T, TViewModel>(this T disposable, View<TViewModel> view) where T : IDisposable | |
{ | |
view.Disposables.Add(disposable); | |
return disposable; | |
} | |
public static void Add(this VisualElement element, IView view) | |
{ | |
element.Add(view.TemplateRoot); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment