Last active
January 11, 2017 13:17
-
-
Save glebov21/12b89550f1d539845e4464187fce82f3 to your computer and use it in GitHub Desktop.
Property bindints without strings
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
public struct Binding | |
{ | |
//WeakReference for garbige collection | |
public System.Reflection.PropertyInfo To; | |
public System.Reflection.PropertyInfo From; //memberinfo, methodinfo | |
public WeakReference ToSource; | |
public WeakReference FromSource; | |
public Delegate Convertation; | |
} | |
public static class Bindings | |
{ | |
private static object BindingLock = new object(); | |
private static Dictionary<object, List<Binding>> allBindings = new Dictionary<object, List<Binding>>(); | |
private static void UpdateBindings<TSource, TProperty>(object view, TSource concreteSource = default(TSource), Expression<Func<TSource, TProperty>> concreteProperty = null) | |
{ | |
lock (BindingLock) | |
{ | |
System.Reflection.PropertyInfo propInfo = null; | |
if (concreteProperty != null) | |
propInfo = GetPropertyInfo(concreteSource, concreteProperty); | |
var viewBind = allBindings[view]; | |
Binding binding; | |
List<Binding> bindingsToRemove = new List<Binding>(); | |
for (int i = 0; i < viewBind.Count; i++) | |
{ | |
binding = viewBind[i]; | |
if (concreteProperty != null) | |
{ | |
if (binding.From != propInfo) | |
continue; | |
} | |
if (!binding.FromSource.IsAlive || !binding.ToSource.IsAlive) | |
{ | |
//if (binding.ToSource.IsAlive) | |
// binding.To.SetValue(binding.ToSource.Target, null, null); //set default value | |
bindingsToRemove.Add(binding); | |
} | |
else | |
{ | |
if (binding.Convertation != null) | |
binding.To.SetValue(binding.ToSource.Target, binding.Convertation.DynamicInvoke(binding.From.GetValue(binding.FromSource.Target))); | |
else | |
binding.To.SetValue(binding.ToSource.Target, binding.From.GetValue(binding.FromSource.Target)); | |
} | |
} | |
foreach (var bindingToRemove in bindingsToRemove) | |
viewBind.Remove(bindingToRemove); | |
} | |
} | |
/// <summary> | |
/// Update all bindings in view | |
/// </summary> | |
public static void UpdateBindings<TSource>(TSource view) | |
{ | |
UpdateBindings<TSource, int>(view); | |
} | |
/// <summary> | |
/// Change property and update bindings from this property | |
/// </summary> | |
public static void SetPropAndUpdateBindings<TSource, TProperty>(object view, TSource source, Expression<Func<TSource, TProperty>> property, TProperty value) | |
{ | |
GetPropertyInfo(source, property).SetValue(source, value); | |
UpdateBindings(view, source, property); | |
} | |
/// <summary> | |
/// Bind objects in this view | |
/// </summary> | |
public static void Bind<TToSource, TToProperty, TFromSource, TFromProperty>(object view, TToSource toSource, Expression<Func<TToSource, TToProperty>> toProperty, TFromSource fromSource, Expression<Func<TFromSource, TFromProperty>> fromProperty, Func<TFromProperty, TToProperty> convertation = null) | |
{ | |
lock (BindingLock) | |
{ | |
if (!allBindings.ContainsKey(view)) | |
allBindings[view] = new List<Binding>(); | |
allBindings[view].Add(new Binding() | |
{ | |
To = GetPropertyInfo<TToSource, TToProperty>(toSource, toProperty), | |
From = GetPropertyInfo<TFromSource, TFromProperty>(fromSource, fromProperty), | |
Convertation = convertation, | |
ToSource = new WeakReference(toSource), | |
FromSource = new WeakReference(fromSource) | |
}); | |
} | |
} | |
private static System.Reflection.PropertyInfo GetPropertyInfo<TSource, TProperty>(TSource source, Expression<Func<TSource, TProperty>> propertyLambda) | |
{ | |
Type type = typeof(TSource); | |
MemberExpression member = propertyLambda.Body as MemberExpression; | |
if (member == null) | |
throw new ArgumentException(string.Format( | |
"Expression '{0}' refers to a method, not a property.", | |
propertyLambda.ToString())); | |
System.Reflection.PropertyInfo propInfo = member.Member as System.Reflection.PropertyInfo; | |
if (propInfo == null) | |
throw new ArgumentException(string.Format( | |
"Expression '{0}' refers to a field, not a property.", | |
propertyLambda.ToString())); | |
if (type != propInfo.ReflectedType && | |
!type.IsSubclassOf(propInfo.ReflectedType)) | |
throw new ArgumentException(string.Format( | |
"Expresion '{0}' refers to a property that is not from type {1}.", | |
propertyLambda.ToString(), | |
type)); | |
return propInfo; | |
} | |
} | |
public class TestClass | |
{ | |
public int TestProp { get; set; } | |
} | |
public class View | |
{ | |
TestClass tFrom = new TestClass(); | |
TestClass tTo = new TestClass(); | |
public View() | |
{ | |
Bindings.Bind(this, tTo, x => x.TestProp, tFrom, x => x.TestProp, (from) => { return from; }); | |
} | |
public void Test() | |
{ | |
tFrom.TestProp = 10; | |
Bindings.UpdateBindings(this); | |
//OR | |
Bindings.SetPropAndUpdateBindings(this, tFrom, x => x.TestProp, 15); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment