Skip to content

Instantly share code, notes, and snippets.

@barsv
Last active September 26, 2020 19:38
Show Gist options
  • Save barsv/46650cf816647ff192fa to your computer and use it in GitHub Desktop.
Save barsv/46650cf816647ff192fa to your computer and use it in GitHub Desktop.
Binding Proof of concept
using System;
using System.Linq.Expressions;
using PostSharp.Aspects;
namespace BindingTest
{
class Program
{
static void Main()
{
var ui = new Ui();
var model = new Model();
// setup two-way binding
Binder.Bind(() => ui.Title, () => model.Title);
Binder.Bind(() => ui.Name, () => model.Name);
// test
model.Title = "change model";
Console.WriteLine("ui.Title=" + ui.Title);
ui.Title = "change ui";
Console.WriteLine("model.Title=" + model.Title);
model.Name = "name test";
Console.WriteLine("ui.Name=" + ui.Name);
Console.WriteLine("ui.Title=" + ui.Title);
Console.WriteLine("model.Title=" + model.Title);
Console.ReadKey();
}
}
public class Ui : Bindable
{
[Bindable]
public string Title { get; set; }
[Bindable]
public string Name { get; set; }
}
public class Model : Bindable
{
[Bindable]
public string Title { get; set; }
[Bindable]
public string Name { get; set; }
}
public class Bindable
{
public delegate void PropertyChangedEventHandler(
Bindable sender, string propertyName);
public event PropertyChangedEventHandler PropertyChanged;
public void OnChange(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, propertyName);
}
public T GetValue<T>(string propertyName)
{
return (T)GetType().GetProperty(propertyName).GetValue(this);
}
}
public class Binder
{
public static void Bind(Expression<Func<object>> m1, Expression<Func<object>> m2)
{
var m1Object = (Bindable)GetParentValue(m1);
var m1PropName = GetPropertyName(m1);
var m2Object = (Bindable)GetParentValue(m2);
var m2PropName = GetPropertyName(m2);
m1Object.PropertyChanged += (sender, name) =>
{
if (name == m1PropName)
{
var valueToSet = sender.GetValue<string>(m1PropName);
m2Object.GetType().GetProperty(m2PropName).SetValue(m2Object, valueToSet);
}
};
m2Object.PropertyChanged += (sender, name) =>
{
if (name == m2PropName)
{
var valueToSet = sender.GetValue<string>(m2PropName);
m1Object.GetType().GetProperty(m1PropName).SetValue(m1Object, valueToSet);
}
};
}
private static object GetParentValue(Expression<Func<object>> prop1)
{
var e = ((MemberExpression)prop1.Body).Expression;
var name = ((MemberExpression)e).Member.Name;
var v = ((ConstantExpression)((MemberExpression)e).Expression).Value;
var f = v.GetType().GetField(name).GetValue(v);
return f;
}
private static string GetPropertyName(Expression<Func<object>> prop1)
{
return ((MemberExpression) prop1.Body).Member.Name;
}
}
[Serializable]
public class BindableAttribute : LocationInterceptionAspect
{
public override void OnSetValue(LocationInterceptionArgs args)
{
var oldValue = args.Instance.GetType().GetProperty(args.LocationName).GetValue(args.Instance);
if (oldValue == args.Value)
return;
base.OnSetValue(args);
((Bindable)args.Instance).OnChange(args.LocationName);
}
}
}
@kingofcrabs
Copy link

Good job!

@JurgenCruz
Copy link

One question. In the Binder class, you are calling the get and setvalue functions with as the generic, but what if your properties are not string? how an the binder know what generic to use?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment