一、目的:通过重写DataGrid的OnAutoGeneratingColumn方法实现根据定义特性自动生成列头信息功能
二、实现
cs
<DataGrid ItemsSource="{local:GetStudents Count=50}"/>
实体定义如下
cs
public class Student
{
[DataGridColumn("*")]
[Display(Name = "姓名", GroupName = "基础信息")]
[Required]
public string Name { get; set; }
[DataGridColumn("*")]
[Display(Name = "班级", GroupName = "基础信息")]
[Required]
public string Class { get; set; }
[DataGridColumn("2*")]
[Display(Name = "地址", GroupName = "基础信息")]
[Required]
public string Address { get; set; }
[DataGridColumn("2*")]
[Display(Name = "邮箱", GroupName = "基础信息")]
[Required]
public string Emall { get; set; }
[Display(Name = "可用", GroupName = "其他信息")]
[Required]
public bool IsEnbled { get; set; }
[Display(Name = "时间", GroupName = "其他信息")]
[Required]
public DateTime Time { get; set; }
[Display(Name = "年龄", GroupName = "基础信息")]
[Required]
public int Age { get; set; }
[Display(Name = "分数", GroupName = "成绩信息")]
public double Score { get; set; }
[DataGridColumn("2*")]
[Display(Name = "电话号码", GroupName = "基础信息")]
[Required]
[RegularExpression("^1[3|4|5|7|8][0-9]{9}$", ErrorMessage = "手机号码不合法!")]
public string Tel { get; set; }
}
通常如上定义会生成一个根据属性名称列头的表格
三、环境
VS2022
四、示例
自定义一个DislayDataGrid,重写OnAutoGeneratingColumn方法
cs
public class DislayDataGrid : DataGrid
{
protected override void OnAutoGeneratingColumn(DataGridAutoGeneratingColumnEventArgs e)
{
base.OnAutoGeneratingColumn(e);
if (e.PropertyDescriptor is PropertyDescriptor descriptor)
e.Column.Header = descriptor.Attributes.OfType<DisplayAttribute>()?.FirstOrDefault().Name;
}
}
此时会根据读取特性生成中文名称列头
同理其他属性也可以这样设置
我们扩展一个特性DataGridColumnAttribute
cs
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public class DataGridColumnAttribute : Attribute, IDataGridColumn
{
public DataGridColumnAttribute(string width)
{
DataGridLengthConverter converter = new DataGridLengthConverter();
this.Width = (DataGridLength)converter.ConvertFromString(width);
}
public DataGridColumnAttribute()
{
}
public DataGridLength Width { get; set; } = DataGridLength.Auto;
public Type Template { get; set; } = typeof(DataGridTextColumn);
/// <summary>
/// "{0}.Property"
/// </summary>
public string PropertyPath { get; set; } = "{0}";
public virtual DataGridColumn GetDataGridColumn(PropertyInfo propertyInfo)
{
DataGridColumn dataGridColumn = Activator.CreateInstance(this.Template) as DataGridColumn;
if (dataGridColumn == null)
{
if (propertyInfo.PropertyType == typeof(bool))
{
return new DataGridCheckBoxColumn() { Width = this.Width, IsReadOnly = false };
}
else if (propertyInfo.PropertyType.IsEnum)
{
return new DataGridComboBoxColumn() { Width = this.Width, IsReadOnly = false };
}
else
{
return new DataGridTextColumn() { Width = this.Width, IsReadOnly = false };
}
}
dataGridColumn.Width = this.Width;
return dataGridColumn;
}
}
在生成列时应用该特性
此时列宽也根据特性变化
如果不想通过自定义DisplayDataGrid实现也可以用Behavior行为的方式实现
实现方式如下:
XML
<DataGrid ItemsSource="{h:GetStudents Count=50}">
<b:Interaction.Behaviors>
<h:DataGridAutoColumnBehavior Type="{x:Type h:Student}"/>
</b:Interaction.Behaviors>
</DataGrid>
DataGridAutoColumnBehavior的具体实现方式如下
这种方式在自动化生成表格数据中非常有用
五、需要了解的知识点
DataGrid 类 (System.Windows.Controls) | Microsoft Learn
六、源码地址
GitHub - HeBianGu/WPF-ControlDemo: 示例
GitHub - HeBianGu/WPF-ControlBase: Wpf封装的自定义控件资源库
GitHub - HeBianGu/WPF-Control: WPF轻量控件和皮肤库