init
This commit is contained in:
88
scripts/FormBinder.cs
Normal file
88
scripts/FormBinder.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using Godot;
|
||||
|
||||
public sealed class FormBinder<TViewModel> where TViewModel : INotifyPropertyChanged
|
||||
{
|
||||
private readonly TViewModel _vm;
|
||||
private readonly Control _root;
|
||||
private readonly Dictionary<LineEdit, PropertyInfo> _lineToProp = new();
|
||||
private readonly Dictionary<string, LineEdit> _propNameToLine = new(StringComparer.OrdinalIgnoreCase);
|
||||
private bool _suppress;
|
||||
|
||||
public FormBinder(TViewModel vm, Control root)
|
||||
{
|
||||
_vm = vm;
|
||||
_root = root;
|
||||
}
|
||||
|
||||
public FormBinder<TViewModel> Bind()
|
||||
{
|
||||
Discover();
|
||||
_vm.PropertyChanged += OnPropertyChanged;
|
||||
foreach (var (line, prop) in _lineToProp)
|
||||
{
|
||||
line.TextChanged += (string text) =>
|
||||
{
|
||||
if (_suppress) return;
|
||||
if (prop.PropertyType == typeof(string) || prop.PropertyType == typeof(string))
|
||||
prop.SetValue(_vm, text);
|
||||
};
|
||||
}
|
||||
// Initial sync UI <- VM
|
||||
PushAllFromVm();
|
||||
return this;
|
||||
}
|
||||
|
||||
private void Discover()
|
||||
{
|
||||
var props = typeof(TViewModel).GetProperties(BindingFlags.Instance | BindingFlags.Public);
|
||||
var propMap = new Dictionary<string, PropertyInfo>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var p in props) if (p.CanRead || p.CanWrite) propMap[p.Name] = p;
|
||||
|
||||
void Walk(Node n)
|
||||
{
|
||||
if (n is LineEdit le)
|
||||
{
|
||||
// Prefer explicit metadata "vm_prop" to map to a property name; fallback to node name.
|
||||
string propName = le.HasMeta("vm_prop") ? (string)le.GetMeta("vm_prop") : StripSuffix(le.Name, "LineEdit");
|
||||
if (propMap.TryGetValue(propName, out var pi))
|
||||
{
|
||||
_lineToProp[le] = pi;
|
||||
_propNameToLine[propName] = le;
|
||||
}
|
||||
}
|
||||
foreach (var c in n.GetChildren())
|
||||
if (c is Node child) Walk(child);
|
||||
}
|
||||
|
||||
Walk(_root);
|
||||
}
|
||||
|
||||
private static string StripSuffix(string s, string suffix) =>
|
||||
s.EndsWith(suffix, StringComparison.Ordinal) ? s[..^suffix.Length] : s;
|
||||
|
||||
private void OnPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == null) return;
|
||||
if (_propNameToLine.TryGetValue(e.PropertyName, out var le))
|
||||
{
|
||||
_suppress = true;
|
||||
try { le.Text = _lineToProp[le].GetValue(_vm)?.ToString() ?? string.Empty; }
|
||||
finally { _suppress = false; }
|
||||
}
|
||||
}
|
||||
|
||||
public void PushAllFromVm()
|
||||
{
|
||||
_suppress = true;
|
||||
try
|
||||
{
|
||||
foreach (var (line, prop) in _lineToProp)
|
||||
line.Text = prop.GetValue(_vm)?.ToString() ?? string.Empty;
|
||||
}
|
||||
finally { _suppress = false; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user