Last active
September 26, 2020 19:38
-
-
Save barsv/46650cf816647ff192fa to your computer and use it in GitHub Desktop.
Binding Proof of concept
This file contains 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.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); | |
} | |
} | |
} |
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
Good job!