wpf 当 AutoGenerateColumns = True 时,如何重命名 DataGrid 列?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13579034/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do you rename DataGrid columns when AutoGenerateColumns = True?
提问by jmulmer
I have a simple data structure class:
我有一个简单的数据结构类:
public class Client {
public String name {set; get;}
public String claim_number {set; get;}
}
Which I am feeding into a DataGrid:
我正在喂食DataGrid:
this.data_grid_clients.ItemSource = this.clients;
I would like to change the column headings. Ie: claim_number to "Claim Number". I know this can be done when you manually create the columns by doing something like:
我想更改列标题。即: claim_number 到“索赔编号”。我知道这可以在您通过执行以下操作手动创建列时完成:
this.data_grid_clients.Columns[0].Header = "Claim Number"
However, the Columnsproperty is empty when auto-generating the columns. Is there a way to rename the columns, or do I have to manually generate the columns?
但是,Columns自动生成列时该属性为空。有没有办法重命名列,还是必须手动生成列?
回答by Ekk
You can use DisplayNameAttributeand update some part of your code to achieve what you want.
您可以使用DisplayNameAttribute并更新代码的某些部分来实现您想要的。
The first thing you have to do is, adding a [DisplayName("")]to properties in the Client class.
您必须做的第一件事是[DisplayName("")]在 Client 类中添加一个to 属性。
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.
更新您的 xaml 代码,将事件处理程序添加到 AutoGenerationColumn 事件。
<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;
}
回答by WoIIe
The nice answer
不错的答案
You can modify the Headerof the auto generated DataGridColumnheader in the AutoGeneratingColumnevent, where you can access the DisplayNameAttribute
您可以在事件中修改Header自动生成的DataGridColumn标题的AutoGeneratingColumn,您可以在其中访问DisplayNameAttribute
Client.cs
客户端.cs
public class Client
{
[DisplayName("Name")]
public String name { set; get; }
[DisplayName("Claim Number")]
public String claim_number { set; get; }
}
.xaml
.xaml
<DataGrid ItemSource="{Binding Clients}"
AutoGenerateColumns="True"
AutoGeneratingColumn="DataGrid_AutoGeneratingColumn" />
.xaml.cs
.xaml.cs
v1
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
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;
}
}
回答by Grafix
You can use the AutoGeneratingColumns event.
您可以使用 AutoGeneratingColumns 事件。
private void dataGridAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
if (e.PropertyName.StartsWith("MyColumn")
e.Column.Header = "Anything I Want";
}
回答by Rob Husband
MVVM answer
MVVM 答案
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.
为了与 MVVM 模式保持一致并避免使用可怕的代码隐藏,您可以使用来自 Sytem.Windows.Interactivity(nuget 上的 Expression Blend SDK 的一部分)的自定义行为。您还需要在创建行为的项目中使用 Windows.Base.dll。
XAML
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.
行为非常有用,不必在与视图相同的项目中定义,这意味着您可以创建行为库并在许多应用程序中使用它们。
回答by WoIIe
The short answer
简短的回答
You can modify the Headerof the auto generated DataGridColumnheader in the AutoGeneratingColumnevent.
您可以在事件中修改Header自动生成的DataGridColumn标题AutoGeneratingColumn。
.xaml
.xaml
<DataGrid ItemSource="{Binding Clients}"
AutoGenerateColumns="True"
AutoGeneratingColumn="DataGrid_AutoGeneratingColumn" />
.xaml.cs
.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;
}
}
回答by Jason Brower
Another Method of Generating Column Headers
生成列标题的另一种方法
To add upon what others have stated in the context of attaching to the OnAutoGeneratingColumn method; I find the following approach useful.
添加其他人在附加到 OnAutoGeneratingColumn 方法的上下文中所说的内容;我发现以下方法很有用。
It will assure that it uses the DisplayName attribute from a view model property just like the others, but if that name is not set it will use regular expressions to take a Pascal cased name and turn it into a nice column header.
它将确保它像其他人一样使用视图模型属性中的 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]))",
@" 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;
}
",
RegexOptions.Compiled)
.Trim();
}
回答by Suplanus
I refactored the answer of Ekk to a shorter and Resharper compatible solution:
我将 Ekk 的答案重构为更短且与 Resharper 兼容的解决方案:
##代码##
