18

我有一个简单的数据结构类:

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自动生成列时该属性为空。有没有办法重命名列,还是我必须手动生成列?

4

7 回答 7

38

您可以使用DisplayNameAttribute并更新代码的某些部分来实现您想要的。

您要做的第一件事是[DisplayName("")]在 Client 类中添加一个 to 属性。

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;
}
于 2012-11-27T07:31:08.890 回答
19

不错的答案

您可以在事件中修改Header自动生成的DataGridColumn标头AutoGeneratingColumn,您可以在其中访问DisplayNameAttribute

客户端.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;
    }
}
于 2018-01-05T22:44:45.203 回答
3

您可以使用 AutoGeneratingColumns 事件。

private void dataGridAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
  if (e.PropertyName.StartsWith("MyColumn")
    e.Column.Header = "Anything I Want";
}
于 2012-11-27T07:29:22.563 回答
2

MVVM 答案

为了使这与 MVVM 模式保持一致并避免使用可怕的代码隐藏,您可以使用 Sytem.Windows.Interactivity 中的自定义行为(在 nuget 上找到的 Expression Blend SDK 的一部分)。您还需要在创建行为的项目中使用 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;
        }
    }
}

行为非常有用,不必与视图在同一个项目中定义,这意味着您可以创建行为库并在许多应用程序中使用它们。

于 2019-09-02T08:13:58.117 回答
1

简短的回答

您可以在事件中修改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;
    }
}
于 2018-01-05T23:02:16.380 回答
0

我将 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;
}
于 2017-02-01T10:42:23.220 回答
-1

另一种生成列标题的方法

添加其他人在附加到 OnAutoGeneratingColumn 方法的上下文中所说的内容;我发现以下方法很有用。

它将确保它使用来自视图模型属性的 DisplayName 属性,就像其他人一样,但是如果未设置该名称,它将使用正则表达式来获取 Pascal 大小写名称并将其转换为漂亮的列标题。

 //Note that I cleaned this up after I pasted it into the Stackoverflow Window, I don't
 //think I caused any compilation errors but you have been warned.
 private void InvoiceDetails_OnAutoGeneratingColumn(object sender,
                                                    DataGridAutoGeneratingColumnEventArgs e)
 {
     if (!(e.PropertyDescriptor is PropertyDescriptor descriptor)) return;

     //You cannot just use descriptor.DisplayName because it provides you a value regardless to it 
     // being manually set.  This approach only uses a DisplayName that was manually set on a view
     // model property.  
     if (descriptor.Attributes[typeof(DisplayNameAttribute)] 
                    is DisplayNameAttribute displayNameAttr
                    && !string.IsNullOrEmpty(displayNameAttr.DisplayName))
     {
         e.Column.Header = displayNameAttr.DisplayName;
         return;
     }

     //If you only wanted to display columns that had DisplayName set you could collapse the ones
     // that didn't with this line.
     //e.Column.Visibility = Visibility.Collapsed;
     //return;

     //This alternative approach uses regular expressions and does not require 
     //DisplayName be manually set.  It will Breakup Pascal named variables 
     //"NamedLikeThis" into nice column headers that are "Named Like This".
     e.Column.Header = Regex.Replace(descriptor.Name,
             @"((?<=[A-Z])([A-Z])(?=[a-z]))|((?<=[a-z]+)([A-Z]))",
             @" $0",
             RegexOptions.Compiled)
            .Trim();

 }
于 2020-05-25T04:40:50.573 回答