How do you rename DataGrid columns when AutoGenerateColumns = True?

The nice answer

You can modify the Header of the auto generated DataGridColumn header in the AutoGeneratingColumn event, where you can access the DisplayNameAttribute

Client.cs

public class Client
{
    [DisplayName("Name")]
    public String name { set; get; }

    [DisplayName("Claim Number")]
    public String claim_number { set; get; }
}

.xaml

<DataGrid ItemSource="{Binding Clients}"
          AutoGenerateColumns="True"
          AutoGeneratingColumn="DataGrid_AutoGeneratingColumn" />

.xaml.cs

v1

// This snippet can be used if you can be sure that every
// member will be decorated with a [DisplayNameAttribute]
private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
    => e.Column.Header = ((PropertyDescriptor)e.PropertyDescriptor)?.DisplayName ?? e.Column.Heaader;

v2

// This snippet is much safer in terms of preventing unwanted
// Exceptions because of missing [DisplayNameAttribute].
private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    if (e.PropertyDescriptor is PropertyDescriptor descriptor)
    {
        e.Column.Header = descriptor.DisplayName ?? descriptor.Name;
    }
}

MVVM answer

In order to keep this consistent with the MVVM pattern and avoid using the horrible code-behind, you can use custom behaviors from Sytem.Windows.Interactivity (part of the Expression Blend SDK found on nuget). You also need Windows.Base.dll in the project where you create the behaviors.

XAML

<DataGrid AutoGenerateColumns="True">
    <i:Interaction.Behaviors>
        <behaviours:ColumnHeaderBehaviour/>
    </i:Interaction.Behaviors>
</DataGrid>

Behaviour Class

public class ColumnHeaderBehaviour : Behavior<DataGrid>
{
    protected override void OnAttached()
    {
        AssociatedObject.AutoGeneratingColumn += OnGeneratingColumn;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.AutoGeneratingColumn -= OnGeneratingColumn;
    }

    private static void OnGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs eventArgs)
    {
        if (eventArgs.PropertyDescriptor is PropertyDescriptor descriptor)
        {
            eventArgs.Column.Header = descriptor.DisplayName ?? descriptor.Name;
        }
        else
        {
            eventArgs.Cancel = true;
        }
    }
}

Behaviors are really useful and don't have to be defined in the same project as your views meaning that you can create a library of behaviors and use them in many applications.


You can use DisplayNameAttribute and update some part of your code to achieve what you want.

The first thing you have to do is, adding a [DisplayName("")] to properties in the Client class.

public class Client {
    [DisplayName("Column Name 1")]
    public String name {set; get;}

    [DisplayName("Clain Number")]
    public String claim_number {set; get;}
}

The update you xaml code, add an event handler to AutoGenerationColumn event.

<dg:DataGrid AutoGenerateColumns="True" AutoGeneratingColumn="OnAutoGeneratingColumn">
</dg:DataGrid>

Finally, add a method to the code-behind.

private void OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    var displayName = GetPropertyDisplayName(e.PropertyDescriptor);

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

}

public static string GetPropertyDisplayName(object descriptor)
{
    var pd = descriptor as PropertyDescriptor;

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

        if (displayName != null && displayName != DisplayNameAttribute.Default)
        {
            return displayName.DisplayName;
        }

    }
    else
    {
        var 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)
            {
                var displayName = attributes[i] as DisplayNameAttribute;
                if (displayName != null && displayName != DisplayNameAttribute.Default)
                {
                    return displayName.DisplayName;
                }
            }
        }
    }

    return null;
}