简体   繁体   中英

Retrieve System.ComponentModel.DataAnnotations.DisplayAttribute properties from ViewModel-bound Controls using code

I've noticed that the SL3 Validators automatically uses the properties from DisplayAttribute when creating validation messages. I'm interested in any suggestions on how to extract this information from a control's binding using code. I've included an example:

ViewModel code:

[Display(Name="First Name")]
public string FirstName { get; set; }

I know can achieve this on a Control-by-Control basis doing something like the following (TextBox in this case):

BindingExpression dataExpression = _firstNameTextBox.GetBindingExpression(TextBox.TextProperty)
Type dataType = dataExpression.DataItem.GetType();
PropertyInfo propInfo = dataType.GetProperty(dataExpression.ParentBinding.Path.Path);
DisplayAttribute attr = propInfo.GetCustomAttributes(false).OfType<DisplayAttribute>().FirstOrDefault();
return (attr == null) ? dataExpression.ParentBinding.Path.Path : attr.Name;

I'm interested if there's any way to do this generically, without needing to know the specific type of Control.

Thanks in advance for any thoughts!!

Good question. Unfortunately there's really no way to generically do it though you can hard code a few properties and be pretty safe. For example, ContentControl.ContentProperty, TextBlock.TextProperty, TextBox.TextProperty, etc.

DataForm in Silverlight does the same thing. I also re-implemented a simple helper method they use called GetPropertyByPath. It basically does what your code does except it can walk a multi-step property path. It can't access indexed properties but neither can DataForm so it's at least as good as that.

From that point on, getting at the DisplayAttribute is just as you've shown.

public static PropertyInfo GetPropertyByPath( object obj, string propertyPath )
{

    ParameterValidation.ThrowIfNullOrWhitespace( propertyPath, "propertyPath" );

    if ( obj == null ) {
        return null;
    }   // if

    Type type = obj.GetType( );

    PropertyInfo propertyInfo = null;
    foreach ( var part in propertyPath.Split( new char[] { '.' } ) ) {

        // On subsequent iterations use the type of the property
        if ( propertyInfo != null ) {
            type = propertyInfo.PropertyType;
        }   // if

        // Get the property at this part
        propertyInfo = type.GetProperty( part );

        // Not found
        if ( propertyInfo == null ) {
            return null;
        }   // if

        // Can't navigate into indexer
        if ( propertyInfo.GetIndexParameters( ).Length > 0 ) {
            return null;
        }   // if

    }   // foreach

    return propertyInfo;

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM