I have a simple class with a property
class Foo
{
string Title { get; set; }
}
I am trying to simplify data binding by calling a fun
Small LINQPad sample of what you want :
void Foo<T>(Expression<Func<T>> prop)
{
var propertyGetExpression = prop.Body as MemberExpression;
// Display the property you are accessing, here "Height"
propertyGetExpression.Member.Name.Dump();
// "s" is replaced by a field access on a compiler-generated class from the closure
var fieldOnClosureExpression = propertyGetExpression.Expression as MemberExpression;
// Find the compiler-generated class
var closureClassExpression = fieldOnClosureExpression.Expression as ConstantExpression;
var closureClassInstance = closureClassExpression.Value;
// Find the field value, in this case it's a reference to the "s" variable
var closureFieldInfo = fieldOnClosureExpression.Member as FieldInfo;
var closureFieldValue = closureFieldInfo.GetValue(closureClassInstance);
closureFieldValue.Dump();
// We know that the Expression is a property access so we get the PropertyInfo instance
// And even access the value (yes compiling the expression would have been simpler :D)
var propertyInfo = propertyGetExpression.Member as PropertyInfo;
var propertyValue = propertyInfo.GetValue(closureFieldValue, null);
propertyValue.Dump();
}
void Main()
{
string s = "Hello world";
Foo(() => s.Length);
}
Well, this is similar in tone to Hangy's solution, but is I think rather comfortable to use and does not require much magic:
public static Binding CreateTextBinding<T>(this T source, Expression<Func<T,object>> access)
{
var mex = access.Body as MemberExpression;
string name = mex.Member.Name;
return new Binding("Text", source, name);
}
This is basically an extension method that can be called on any object acting as source. It gives you back a Binding for a Text property which you can add to any Bindings collection.
Something like the following should work:
void BindToText<T>(Control control, Expression<Func<T>> property)
{
var mex = property.Body as MemberExpression;
string name = mex.Member.Name;
var fooMember = mex.Expression as MemberExpression;
var fooConstant = fooMember.Expression as ConstantExpression;
var foo = fooConstant.Value;
control.DataBindings.Add("Text", foo, name);
}
Let me know if that doesn't work for you.
Don't. Just modify the method to take another parameter, as described in #3444294. For your example, it may be something like this:
void BindToText<T>(Control control, T dataSource, Expression<Func<T>> property)
{
var mex = property.Body as MemberExpression;
string name = mex.Member.Name;
control.DataBindings.Add("Text", dataSource, name);
}
and would be called like
BindToText(titleTextBox, foo, ()=>foo.Title );
Still nice, but easy to understand. There's no magic happening. ;)