Loading...
[-]

Getting WPF DataGrid column headers to use the DisplayName property attribute

The source code to this post is here (requires VS2010): DataGridDisplayNameTest.zip

One of the great things about the new DataGrid in .NET 4.0 is that it allows you to just assign a collection to its ItemSource and it auto generates the columns for you. Great!

I had a class that looked like this:

  public class TestItem {
    [DisplayName("Display Name 1")]
    public int Value1 { get; set; }

    [DisplayName("Display Name 2")]
    public int Value2 { get; set; }

    [DisplayName("Display Name 3")]
    public int Value3 { get; set; }
  }

However when I put a list of these into the DataGrid I didn’t get the Display Name as the column header but rather I got the property name like so:

This next image shows what I wanted:

The new DataGrid started out life as part of the WPF toolkit, I’d figured that the original control needed a fix and so I posted a patch at wpf.codeplex.com, however until that patch was applied to the release version it wasn’t going to get around my immediate problem, so I came up with the solution below which handles the AutoGeneratingColumn event in the DataGrid to set the headings.

MainWindow.xaml:

<Window x:Class="DataGridDisplayNameTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        xmlns:dg="clr-namespace:System.Windows.Controls;assembly=PresentationFramework">
    <Grid>
      <dg:DataGrid x:Name="theGrid" AutoGenerateColumns="True" AutoGeneratingColumn="dg_AutoGeneratingColumn">
      </dg:DataGrid>
  </Grid>
</Window>

MainWindow.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Reflection;

namespace DataGridDisplayNameTest {

  /// <summary>
  /// This test app demonstrates how to set the Column Headers in the WPF DataGrid
  /// to the display name attribute of the bound property.
  /// </summary>
  public partial class MainWindow : Window {
    public MainWindow() {
      this.Initialized += new EventHandler(MainWindow_Initialized);
      InitializeComponent();
    }

    /// <summary>
    /// Add data to controls after they have been initialized
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void MainWindow_Initialized(object sender, EventArgs e) {
      this.theGrid.ItemsSource = new ObservableCollection<TestItem>{
        new TestItem {
          Value1 = 11, Value2 = 12, Value3 = 13 
        },
        new TestItem {
          Value1 = 21, Value2 = 22, Value3 = 23 
        },
        new TestItem {
          Value1 = 31, Value2 = 32, Value3 = 33 
        }
      };
    }

    /// <summary>
    /// Event handler for when columns are added to the data grid
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void dg_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e) {

      string displayName = GetPropertyDisplayName(e.PropertyDescriptor);
      if (!string.IsNullOrEmpty(displayName)) {
        e.Column.Header = displayName;
      }

    }

    /// <summary>
    /// Gets the Display Name for the property descriptor passed in
    /// </summary>
    /// <param name="descriptor"></param>
    /// <returns></returns>
    public static string GetPropertyDisplayName(object descriptor) {

      PropertyDescriptor pd = descriptor as PropertyDescriptor;
      if (pd != null) {
        // Check for DisplayName attribute and set the column header accordingly
        DisplayNameAttribute displayName = pd.Attributes[typeof(DisplayNameAttribute)] as DisplayNameAttribute;
        if (displayName != null && displayName != DisplayNameAttribute.Default) {
          return displayName.DisplayName;
        }

      } else {
        PropertyInfo pi = descriptor as PropertyInfo;
        if (pi != null) {
          // Check for DisplayName attribute and set the column header accordingly
          Object[] attributes = pi.GetCustomAttributes(typeof(DisplayNameAttribute), true);
          for (int i = 0; i < attributes.Length; ++i) {
            DisplayNameAttribute displayName = attributes[i] as DisplayNameAttribute;
            if (displayName != null && displayName != DisplayNameAttribute.Default) {
              return displayName.DisplayName;
            }
          }
        }
      }
      return null;
    }

  }

  public class TestItem {
    [DisplayName("Display Name 1")]
    public int Value1 { get; set; }
    [DisplayName("Display Name 2")]
    public int Value2 { get; set; }
    [DisplayName("Display Name 3")]
    public int Value3 { get; set; }

  }
}

2 Comments

  1. Posted April 15, 2014 at 22:23 | Permalink

    Just simplify DataGrid’s event this way:

    void dg_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e) {
    PropertyDescriptor pd = (PropertyDescriptor)e.PropertyDescriptor;
    e.Column.Header = pd.DisplayName;
    }

    easy
    :)

  2. Jake
    Posted September 16, 2014 at 20:22 | Permalink

    Thanks :)

Post a Comment

Your email is never shared. Required fields are marked *

*
*