You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,
        });
    }

错误原因分析

  1. 数据读取遗漏第一行:开头的if(dr.Read())已经读取了查询结果的第一行数据,导致后续while(dr.Read())只能从第二行开始读取,最终dataForDatagrid的元素数量比实际总数据量少1。
  2. 索引越界触发:通过COUNT(scenarioID) OVER ()获取的dataCount是数据库中实际的总行数,但dataForDatagrid的元素数量少1,循环for (int j = 0; j < dataCount; ++j)会在j等于dataForDatagrid.Count时访问不存在的索引,触发越界错误。
  3. 额外问题:列重复显示: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 19:57:25