How to get the underlying data type of a bound property?
For testing purposes I created a viewmodel 'Person' with a property 'Age' of type Int32, that is bound to a textbox's text property.
Is there something like ...
BindingOperations.GetBindingExpression(this, TextBox.TextProperty).PropertyType
or can this information only be retrieved by reflection?
myBinding.Source.GetType().GetProperty("Age").PropertyType
Edit:
I have a custom textbox class, where I want to attach my own validationrules, converters ...
It would be great to get the information inside f.e. the 'load'-event of the textbox class.
You could get the value inside the Convert method of a converter:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
value.GetType(); / *The bound object is here
}
XAML
Text="{Binding Age, Mode=TwoWay,Converter={StaticResource converterName}}"
Not sure where you need access to the type, but it is available at that level, if you needed to transform the value.
if the property is bound to a specific datatype you need to set the value in the text box to a valid value for the property before it will update the viewmodel source
It seems that any validation errors stop the view model updating. Which I think is rubbish.
The only way I have found to do this is by using reflection. The following code gets the binded object. It also handles nested binding {Binding Parent.Value}
and if a converter is present - it returns the converted value. The method also returns the item's type for the cases in which the item is null.
private static object GetBindedItem(FrameworkElement fe, out Type bindedItemType)
{
bindedItemType = null;
var exp = fe.GetBindingExpression(TextBox.TextProperty);
if (exp == null || exp.ParentBinding == null || exp.ParentBinding.Path == null
|| exp.ParentBinding.Path.Path == null)
return null;
string bindingPath = exp.ParentBinding.Path.Path;
string[] elements = bindingPath.Split('.');
var item = GetItem(fe.DataContext, elements, out bindedItemType);
// If a converter is used - don't ignore it
if (exp.ParentBinding.Converter != null)
{
var convOutput = exp.ParentBinding.Converter.Convert(item,
bindedItemType, exp.ParentBinding.ConverterParameter, CultureInfo.CurrentCulture);
if (convOutput != null)
{
item = convOutput;
bindedItemType = convOutput.GetType();
}
}
return item;
}
private static object GetItem(object data, string[] elements, out Type itemType)
{
if (elements.Length == 0)
{
itemType = data.GetType();
return data;
}
if (elements.Length == 1)
{
var accesor = data.GetType().GetProperty(elements[0]);
itemType = accesor.PropertyType;
return accesor.GetValue(data, null);
}
string[] innerElements = elements.Skip(1).ToArray();
object innerData = data.GetType().GetProperty(elements[0]).GetValue(data);
return GetItem(innerData, innerElements, out itemType);
}