如何给已绑定数据库数据的WPF DataGrid添加自定义列及值?
问题解决与自定义列实现方案
先解决No.列空白问题
你的SQL查询仅获取了scenarioName和scenarioDate,但XAML绑定的scenarioID字段并不在查询结果里,DataTable自然没有这个数据,导致列空白。修改SQL语句,把scenarioID加入查询即可:
string sql = "SELECT scenarioID, scenarioName, scenarioDate FROM tbl_scenario";
重新填充DataTable后,scenarioID字段会存在,绑定就能正常显示序号。
添加自定义列(含非数据库来源列)
下面提供两种常用实现方式,按需选择:
方式一:直接扩展DataTable(快速实现)
无需额外实体类,直接给DataTable新增列并赋值,适合小型场景:
// 填充DataTable后添加自定义列 DataTable dtScenario = new DataTable(); sqlDataAdapter.Fill(dtScenario); // 1. 添加计算值列(比如根据日期判断状态) dtScenario.Columns.Add("Status", typeof(string)); foreach (DataRow row in dtScenario.Rows) { DateTime date = Convert.ToDateTime(row["scenarioDate"]); row["Status"] = date < DateTime.Today ? "已过期" : "正常"; } // 2. 添加固定标识列(用于后续XAML中的操作按钮) dtScenario.Columns.Add("Action", typeof(string)); foreach (DataRow row in dtScenario.Rows) { row["Action"] = "操作"; } // 重新绑定 scenarioDataGrid.ItemsSource = dtScenario.DefaultView;
对应的XAML列定义:
<DataGrid.Columns> <DataGridTextColumn Binding="{Binding scenarioID}" Header="No." Width="50" IsReadOnly="True"/> <DataGridTextColumn Binding="{Binding scenarioName}" Header="场景名称" Width="150" IsReadOnly="True"/> <DataGridTextColumn Binding="{Binding scenarioDate}" Header="创建日期" Width="120" IsReadOnly="True"/> <DataGridTextColumn Binding="{Binding Status}" Header="状态" Width="80" IsReadOnly="True"/> <!-- 自定义操作列(用TemplateColumn放按钮) --> <DataGridTemplateColumn Header="操作" Width="80"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Button Content="编辑" Click="EditScenario_Click"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns>
方式二:使用实体类(推荐WPF开发模式)
这种方式更符合WPF的MVVM思想,便于维护和扩展,适合中大型项目:
- 创建包含数据库字段和自定义属性的实体类:
public class Scenario { public int ScenarioID { get; set; } public string ScenarioName { get; set; } public DateTime ScenarioDate { get; set; } // 自定义计算属性(非数据库来源) public string Status => ScenarioDate < DateTime.Today ? "已过期" : "正常"; // 自定义固定属性 public string ButtonText => "编辑"; }
- 从数据库读取数据并转换为实体类列表:
List<Scenario> scenarioList = new List<Scenario>(); conn.Open(); using (SqlCommand cmd = new SqlCommand("SELECT scenarioID, scenarioName, scenarioDate FROM tbl_scenario", conn)) { SqlDataReader reader = cmd.ExecuteReader(); while (reader.Read()) { scenarioList.Add(new Scenario { ScenarioID = reader.GetInt32(0), ScenarioName = reader.GetString(1), ScenarioDate = reader.GetDateTime(2) }); } } conn.Close(); // 直接绑定实体列表 scenarioDataGrid.ItemsSource = scenarioList;
- XAML绑定实体属性:
<DataGrid.Columns> <DataGridTextColumn Binding="{Binding ScenarioID}" Header="No." Width="50" IsReadOnly="True"/> <DataGridTextColumn Binding="{Binding ScenarioName}" Header="场景名称" Width="150" IsReadOnly="True"/> <DataGridTextColumn Binding="{Binding ScenarioDate}" Header="创建日期" Width="120" IsReadOnly="True"/> <DataGridTextColumn Binding="{Binding Status}" Header="状态" Width="80" IsReadOnly="True"/> <DataGridTemplateColumn Header="操作" Width="80"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Button Content="{Binding ButtonText}" Click="EditScenario_Click"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns>
额外需求:显示行号(不依赖数据库ID)
如果不需要数据库的scenarioID,只想显示DataGrid的行序号,可以通过LoadingRow事件实现:
private void scenarioDataGrid_LoadingRow(object sender, DataGridRowEventArgs e) { // 行号从1开始计数 e.Row.Header = (e.Row.GetIndex() + 1).ToString(); }
XAML开启行头显示:
<DataGrid x:Name="scenarioDataGrid" LoadingRow="scenarioDataGrid_LoadingRow" HeadersVisibility="All">
内容的提问来源于stack exchange,提问作者Xue Xian Heah
相关产品推荐
相关产品推荐

