16

How can i access DisplayName's value in XAML?

I've got:

public class ViewModel {
  [DisplayName("My simple property")]
  public string Property {
    get { return "property";}
  }
}

XAML:

<TextBlock Text="{Binding ??Property.DisplayName??}"/>
<TextBlock Text="{Binding Property}"/>

Is there any way to bind DisplayName in such or simmilar way? The best idea will be to use this DisplayName as key to Resources and present something from Resources.

H.B.
  • 166,899
  • 29
  • 327
  • 400
Simon
  • 2,329
  • 4
  • 30
  • 49

2 Answers2

24

I would use a markup extension:

public class DisplayNameExtension : MarkupExtension
{
    public Type Type { get; set; }

    public string PropertyName { get; set; }

    public DisplayNameExtension() { }
    public DisplayNameExtension(string propertyName)
    {
        PropertyName = propertyName;
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        // (This code has zero tolerance)
        var prop = Type.GetProperty(PropertyName);
        var attributes = prop.GetCustomAttributes(typeof(DisplayNameAttribute), false);
        return (attributes[0] as DisplayNameAttribute).DisplayName;
    }
}

Example usage:

<TextBlock Text="{m:DisplayName TestInt, Type=local:MainWindow}"/>
public partial class MainWindow : Window
{
   [DisplayName("Awesome Int")]
   public int TestInt { get; set; }
   //...
}
H.B.
  • 166,899
  • 29
  • 327
  • 400
  • 4
    I would also go with a MarkupExtension but that leverages a custom localizable DisplayNameAttribute as shown [here](http://stackoverflow.com/questions/356464/localization-of-displaynameattribute) – CodeNaked May 28 '11 at 00:18
  • @CodeNaked: Good idea, while i was aware of localizaton issues i didn't think of any particular approach myself. – H.B. May 28 '11 at 00:25
  • Any Idea how can we make it working if underlying type is generic object? – Gaurav Gupta Oct 30 '15 at 09:14
  • 2
    @GauravGupta: The type owning the property? If so you need something like `{m:DisplayName Property, Type={x:Type local:MyType\`1}}` where the number refers to the number of generic arguments. [Here's an example of using generics in XAML](http://stackoverflow.com/a/8235459/546730). – H.B. Oct 30 '15 at 17:12
8

Not sure how well this would scale, but you could use a converter to get to your DisplayName. The converter would look something like:

public class DisplayNameConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        PropertyInfo propInfo = value.GetType().GetProperty(parameter.ToString());
        var attrib = propInfo.GetCustomAttributes(typeof(System.ComponentModel.DisplayNameAttribute), false);

        if (attrib.Count() > 0)
        {
            return ((System.ComponentModel.DisplayNameAttribute)attrib.First()).DisplayName;
        }

        return String.Empty;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

and then your binding in XAML would look like:

Text="{Binding Mode=OneWay, Converter={StaticResource ResourceKey=myConverter}, ConverterParameter=MyPropertyName}"
Greg Andora
  • 1,372
  • 2
  • 11
  • 17