C# WPF DataGrid索引越界问题:数据库数据绑定异常排查
问题:WPF DataGrid绑定数据时出现索引越界错误
我正在开发C# WPF桌面应用,需从数据库获取数据并展示在DataGrid中。目前已成功获取部分数据,但出现「Index was out of range. Must be non-negative and less than the size of the collection. Parameter 'index'」错误。
相关代码与信息
DataGrid的XAML代码
<DataGrid Grid.Row="1" x:Name="scenarioDataGrid" CanUserSortColumns="True" IsReadOnly="True" AutoGenerateColumns="True" Grid.ColumnSpan="3" Margin="53,40,53,10" Grid.RowSpan="3"> <DataGrid.Columns> <DataGridTextColumn x:Name="scenarioNumberColumn" Binding="{Binding scenarioNum}" Header="No." Width="50" IsReadOnly="True"/> <DataGridTextColumn x:Name="scenarioNameColumn" Binding="{Binding scenarioName}" Header="Scenario Name" Width="*" IsReadOnly="True"/> <DataGridTextColumn x:Name="scenarioDateColumn" Binding="{Binding scenarioDate}" Header="Date" Width="*" IsReadOnly="True"/> </DataGrid.Columns> </DataGrid>
自定义ScenarioData类
public class ScenarioData { public int scenarioNum { get; set; } public string? scenarioName { get; set; } public string? scenarioDate { get; set; } }
数据库数据查询与绑定代码
conn.Open(); string sql = "SELECT COUNT(scenarioID) OVER () AS 'Num', scenarioName AS 'Scenario Name', scenarioDate AS 'Scenario Date' FROM tbl_scenario"; SqlCommand cmd = new SqlCommand(sql, conn); SqlDataReader dr = cmd.ExecuteReader(); if(dr.Read()) { int dataCount = Convert.ToInt32(dr["Num"].ToString()); List<ScenarioData> dataForDatagrid = new List<ScenarioData>(); while (dr.Read()) { dataForDatagrid.Add(new ScenarioData() { scenarioName = dr["Scenario Name"].ToString(), scenarioDate = dr["Scenario Date"].ToString(), }); } for (int j = 0; j < dataCount; ++j) { scenarioDataGrid.Items.Add(new ScenarioData() { scenarioNum = j+1, scenarioName = dataForDatagrid[j].scenarioName, scenarioDate = dataForDatagrid[j].scenarioDate, }); }
错误原因分析
- 数据读取遗漏第一行:开头的
if(dr.Read())已经读取了查询结果的第一行数据,导致后续while(dr.Read())只能从第二行开始读取,最终dataForDatagrid的元素数量比实际总数据量少1。 - 索引越界触发:通过
COUNT(scenarioID) OVER ()获取的dataCount是数据库中实际的总行数,但dataForDatagrid的元素数量少1,循环for (int j = 0; j < dataCount; ++j)会在j等于dataForDatagrid.Count时访问不存在的索引,触发越界错误。 - 额外问题:列重复显示:XAML中设置了
AutoGenerateColumns="True",同时手动定义了列,会导致DataGrid显示重复列,影响界面效果。
修正方案
1. 修正数据读取逻辑
去掉多余的if(dr.Read()),直接通过while读取所有行,同时在读取时直接生成带序号的ScenarioData对象,无需后续循环:
conn.Open(); // 不需要COUNT OVER,直接读取数据即可 string sql = "SELECT scenarioName AS 'Scenario Name', scenarioDate AS 'Scenario Date' FROM tbl_scenario"; SqlCommand cmd = new SqlCommand(sql, conn); SqlDataReader dr = cmd.ExecuteReader(); List<ScenarioData> dataForDatagrid = new List<ScenarioData>(); int rowNumber = 1; while (dr.Read()) { dataForDatagrid.Add(new ScenarioData() { scenarioNum = rowNumber++, scenarioName = dr["Scenario Name"].ToString(), scenarioDate = dr["Scenario Date"].ToString(), }); } // 使用ItemsSource绑定数据,比逐个Add更高效 scenarioDataGrid.ItemsSource = dataForDatagrid;
2. 修正DataGrid列设置
将XAML中的AutoGenerateColumns="True"改为AutoGenerateColumns="False",避免列重复:
<DataGrid Grid.Row="1" x:Name="scenarioDataGrid" CanUserSortColumns="True" IsReadOnly="True" AutoGenerateColumns="False" Grid.ColumnSpan="3" Margin="53,40,53,10" Grid.RowSpan="3"> <DataGrid.Columns> <DataGridTextColumn x:Name="scenarioNumberColumn" Binding="{Binding scenarioNum}" Header="No." Width="50" IsReadOnly="True"/> <DataGridTextColumn x:Name="scenarioNameColumn" Binding="{Binding scenarioName}" Header="Scenario Name" Width="*" IsReadOnly="True"/> <DataGridTextColumn x:Name="scenarioDateColumn" Binding="{Binding scenarioDate}" Header="Date" Width="*" IsReadOnly="True"/> </DataGrid.Columns> </DataGrid>
补充建议
- 建议使用
using语句包裹SqlConnection、SqlCommand、SqlDataReader,确保资源自动释放,避免内存泄漏:using (SqlConnection conn = new SqlConnection(connectionString)) { conn.Open(); using (SqlCommand cmd = new SqlCommand(sql, conn)) { using (SqlDataReader dr = cmd.ExecuteReader()) { // 读取数据逻辑 } } } - 若后续功能复杂,建议采用MVVM模式,通过绑定
ObservableCollection<T>到ItemsSource,实现数据的自动更新。
内容的提问来源于stack exchange,提问作者Xue Xian Heah
相关产品推荐
相关产品推荐

