Как вы переименовываете столбцы DataGrid при AutoGenerateColumns = True?

У меня есть простой класс структуры данных:

public class Client {
    public String name {set; get;}
    public String claim_number {set; get;}
}

Что я кормлю в DataGrid:

this.data_grid_clients.ItemSource = this.clients;

Я хотел бы изменить заголовки столбцов. Т.е.: Claim_number на "Номер претензии". Я знаю, что это можно сделать, когда вы вручную создаете столбцы, делая что-то вроде:

this.data_grid_clients.Columns[0].Header = "Claim Number"

Однако при автогенерации столбцов свойство Columns пуст. Есть ли способ переименовать столбцы или мне нужно вручную создавать столбцы?

Ответ 1

Вы можете использовать DisplayNameAttribute и обновить часть кода для достижения желаемого.

Первое, что вам нужно сделать, это добавить свойства [DisplayName("")] к свойствам в классе Client.

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

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

Обновите свой код xaml, добавьте обработчик события в событие AutoGenerationColumn.

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

Наконец, добавьте метод для кода.

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;
}

Ответ 2

Хороший ответ

Вы можете изменить Header автоматически сгенерированного заголовка DataGridColumn в событии AutoGeneratingColumn, где вы можете получить доступ к 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;

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;
    }
}

Ответ 3

Вы можете использовать событие AutoGeneratingColumns.

private void dataGridAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
  if (e.PropertyName.StartsWith("MyColumn")
    e.Column.Header = "Anything I Want";
}

Ответ 4

MVVM ответ

Чтобы сохранить это в соответствии с шаблоном MVVM и избежать использования ужасного кода, вы можете использовать пользовательские поведения из Sytem.Windows.Interactivity (часть SDK Expression Blend, найденного в nuget). Вам также понадобится Windows.Base.dll в проекте, где вы создаете поведение.

XAML

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

Класс поведения

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;
        }
    }
}

Поведения действительно полезны и не должны быть определены в том же проекте, что и ваши представления, что означает, что вы можете создать библиотеку поведений и использовать их во многих приложениях.

Ответ 5

Я реорганизовал ответ Ekk на более короткое и совместимое с Resharper решение:

public static string GetPropertyDisplayName(object descriptor)
{
   var propertyDescriptor = descriptor as PropertyDescriptor;
   if (propertyDescriptor != null)
   {
      var displayName = propertyDescriptor.Attributes[typeof(DisplayNameAttribute)] as DisplayNameAttribute;
      if (displayName != null && !Equals(displayName, DisplayNameAttribute.Default))
      {
         return displayName.DisplayName;
      }
   }
   else
   {
      var propertyInfo = descriptor as PropertyInfo;
      if (propertyInfo != null)
      {
         var attributes = propertyInfo.GetCustomAttributes(typeof(DisplayNameAttribute), true);
         foreach (object attribute in attributes)
         {
            var displayName = attribute as DisplayNameAttribute;
            if (displayName != null && !Equals(displayName, DisplayNameAttribute.Default))
            {
               return displayName.DisplayName;
            }
         }
      }
   }
   return null;
}

Ответ 6

Короткий ответ

Вы можете изменить Header автоматически сгенерированного DataGridColumn в событии AutoGeneratingColumn.

.xaml

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

.xaml.cs

private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    switch (e.Name)
    {
        case nameof(Client.name):
            e.Column.Header = "Name";
            break;

        case nameof(Client.claim_number):
            e.Column.Header = "Claim Number";
            break;
    }
}