Hi does anyone know if there are any inbuilt classes for resolving a bound object from a bindingexpression and it\'s DataItem and property path?
I\'m attempting to w
For people in the future who stumble on this question:
When .NET 4.5 becomes available it will have a number of new properties on the BindingExpression to greatly simplify what you are looking for.
ResolvedSource - The object that is actually being bound to, helpful when you have a binding source like 'grandparent.parent.me.Name'. This would return the 'me' object.
ResolvedSourcePropertyName - The name of the property on the ResolvedSource that is bound to. In the case above, "Name".
Similarly, there will be Target, and TargetName properties.
With these helper properties on BindingExpression you could use some shorter and much more simplified reflection that is more likely to work in extreme situations (indexers).
As Dan Bryant already noted, PropertyPath
resolution is tightly coupled with the overall binding architecture.
If you need the exact same resolution as WPF does it, you should probably use Thomas Levesque's answer to this question.
However, if you just need general path resolution, you can use a nuget package Pather.CSharp I developed that does exactly that.
It is essentially similar to zhech's answer, but more sophisticated.
Its main method is Resolve
on the Resolver
class. Passing in the target object and a path as string returns the desired result.
An Example:
IResolver resolver = new Resolver();
var target = new { Property1 = new { Property2 = "value" } };
object result = r.Resolve(target, "Property1.Property2");
It also supports collection access via index or dictionary access via key.
Example paths for these are:
"ArrayProperty[5]"
"DictionaryProperty[Key]"
Below is a quick implementation for an extension method that will do just what you are looking for. I couldn't find anything related to this either. The method below will always return null if for some reason the value cannot be found. The method won't work when the path includes []. I hope this helps!
public static T GetValue<T>(this BindingExpression expression, object dataItem)
{
if (expression == null || dataItem == null)
{
return default(T);
}
string bindingPath = expression.ParentBinding.Path.Path;
string[] properties = bindingPath.Split('.');
object currentObject = dataItem;
Type currentType = null;
for (int i = 0; i < properties.Length; i++)
{
currentType = currentObject.GetType();
PropertyInfo property = currentType.GetProperty(properties[i]);
if (property == null)
{
currentObject = null;
break;
}
currentObject = property.GetValue(currentObject, null);
if (currentObject == null)
{
break;
}
}
return (T)currentObject;
}
I believe this other StackOverflow solution posted here may also work for you.
Copied code block for reference, read original post for more details provided by Thomas Levesque.
public static class PropertyPathHelper
{
public static object GetValue(object obj, string propertyPath)
{
Binding binding = new Binding(propertyPath);
binding.Mode = BindingMode.OneTime;
binding.Source = obj;
BindingOperations.SetBinding(_dummy, Dummy.ValueProperty, binding);
return _dummy.GetValue(Dummy.ValueProperty);
}
private static readonly Dummy _dummy = new Dummy();
private class Dummy : DependencyObject
{
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(Dummy), new UIPropertyMetadata(null));
}
}
Just for further information, PropertyPath resolution is handled by an internal MS class called PropertyPathWorker, which lives in PresentationFramework under MS.Internal.Data. If you open it up in Reflector, you can see it's quite complicated, so I wouldn't recommend trying to duplicate its functionality. It's tightly coupled with the overall Binding architecture.
The most robust way to support all property path syntax--including attached dependency properties and hierarchical traversal--is probably to create a dummy DependencyObject with a DependencyProperty. You can then create a Binding from your 'owner' path to the dummy dependency property, create a new BindingExpression and then call the expression's UpdateTarget. It's a rather heavy way of accomplishing what, on the surface, looks like a simple task, but I think there are a lot of hidden gotchas in the way property paths are resolved for binding.