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

WPF重新加载后DataGrid不显示ObservableCollection的问题排查

问题:刷新ObservableCollection后DataGrid为空的原因及解决方法

首次加载发票数据时,ObservableCollection能正常显示在DataGrid中,但执行按钮触发的Refresh方法后,DataGrid变为空状态。以下是相关代码及排查修复方案:

相关代码

集合属性定义

private ObservableCollection<InvoiceData> _listAchats;
public ObservableCollection<InvoiceData> ListAchats
{
    get { return _listAchats; }
    set
    {
        _listAchats = value;
        NotifyPropertyChanged("ListAchats");
    }
}

ViewModel初始化及数据查询方法

_listAchats = new ObservableCollection<InvoiceData>();
ListAchats = GetAchatList();

public ObservableCollection<InvoiceData> GetAchatList()
{
    ObservableCollection<InvoiceData> ClientsList = new ObservableCollection<InvoiceData>();

    using (SQLiteConnection conn =
        new SQLiteConnection(ConfigurationManager.ConnectionStrings["StringConnexion"].ConnectionString))
    {
        conn.Open();

        SQLiteCommand cmdNotes =
            new SQLiteCommand("SELECT * FROM Invoice", conn);

        using (SQLiteDataReader reader = cmdNotes.ExecuteReader())
        {
            var ordinals = new
            {
                InvoiceId = reader.GetOrdinal("invoice_id"),
                SellerName = reader.GetOrdinal("seller_name"),
                PurchaseDate = reader.GetOrdinal("purchase_date")
            };

            while (reader.Read())
            {
                var temp = new TableInvoice();
                temp.IdInvoice = reader.GetInt32(ordinals.InvoiceId);
                temp.SellerName = reader.GetString(ordinals.SellerName);
                temp.PurchaseDate = reader.GetDateTime(ordinals.PurchaseDate).ToShortDateString();
                ClientsList.Add(temp.ClientsList());
            }
        }
    }
    return ClientsList;
}

Refresh方法

private void Refresh()
{
    Console.WriteLine("This is triggered");
    ListAchats.Clear();
    ListAchats = GetAchatList();
    Console.WriteLine(ListAchats.Count);
}

DataGrid XAML绑定

<DataGrid Margin="0 16 0 0"
          Name="Agrid"
          Background="Transparent"
          ScrollViewer.CanContentScroll="True" 
          ScrollViewer.VerticalScrollBarVisibility="Auto"
          AutoGenerateColumns="False"
          Focusable="False"
          MaxHeight="400"
          ScrollViewer.HorizontalScrollBarVisibility="Auto"
          CanUserSortColumns="True"
          SelectedItem="{Binding SelectedAchat}"
          ItemsSource="{Binding ListAchats,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
          CanUserAddRows="False"
          IsReadOnly="True" SelectionMode="Single" SelectionUnit="FullRow">
    <DataGrid.InputBindings>
        <KeyBinding Key="Delete" Command="{Binding DeleteButtonCommand}"/>
    </DataGrid.InputBindings>
    <DataGrid.Columns>
        <DataGridTemplateColumn SortMemberPath="IdInvoice"  Header="N° Achat">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock VerticalAlignment="Center"
                               Text="{Binding Path=IdInvoice, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn  SortMemberPath="SellerName" Header="Nom de vendeur" >
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock VerticalAlignment="Center"
                                Text="{Binding Path=SellerName, Mode=TwoWay}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn SortMemberPath="PurchaseDate"  Header="Date d'achat" >
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock VerticalAlignment="Center"
                               Text="{Binding Path=PurchaseDate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

可能原因及修复方案

1. 数据查询未返回结果

先查看Console.WriteLine(ListAchats.Count)的输出值:

  • 如果输出为0,说明GetAchatList()从数据库未查询到数据。排查方向:
    • 确认插入数据的逻辑已正确提交到数据库(比如是否调用了ExecuteNonQuery()且事务已提交);
    • 检查数据库连接字符串是否指向正确的数据库文件;
    • 验证查询语句SELECT * FROM Invoice是否能返回新插入的数据(可直接在数据库工具中执行该语句)。

2. 线程上下文问题

如果Refresh方法在后台线程中执行(比如异步插入操作完成后回调),直接修改ObservableCollection会导致UI无法接收更新通知,因为WPF的UI元素只能在UI线程更新。修复方式:切换到UI线程执行刷新逻辑:

private void Refresh()
{
    Application.Current.Dispatcher.Invoke(() =>
    {
        Console.WriteLine("This is triggered");
        var newList = GetAchatList();
        Console.WriteLine(newList.Count);
        ListAchats = newList;
    });
}

3. 集合操作逻辑缺陷

原Refresh方法先调用ListAchats.Clear()再赋值新集合,会导致UI短暂处于空状态,若后续赋值过程出现异常或数据未正确加载,就会保持为空。优化逻辑:先获取新数据再赋值,避免中间空状态:

private void Refresh()
{
    Console.WriteLine("This is triggered");
    // 先获取完整的新数据集合
    var newInvoiceList = GetAchatList();
    Console.WriteLine(newInvoiceList.Count);
    // 直接替换集合,触发PropertyChanged通知UI更新
    ListAchats = newInvoiceList;
}

如果需要保留原集合实例(比如维护用户选中项等),可改为清空后添加新元素:

private void Refresh()
{
    Console.WriteLine("This is triggered");
    var newInvoiceList = GetAchatList();
    Console.WriteLine(newInvoiceList.Count);
    
    ListAchats.Clear();
    foreach(var invoice in newInvoiceList)
    {
        ListAchats.Add(invoice);
    }
}

4. 数据类型不匹配

确认temp.ClientsList()返回的是InvoiceData类型,因为ListAchats是ObservableCollection<InvoiceData>。如果返回类型不匹配,集合中的元素无法被DataGrid正确绑定,导致显示为空。可在GetAchatList方法中添加断点,检查ClientsList内元素的类型是否正确。

5. 绑定模式冗余

DataGrid的ItemsSource绑定不需要TwoWay模式(TwoWay适用于可编辑的输入控件,而ItemsSource是单向的数据源绑定),修改绑定为:

ItemsSource="{Binding ListAchats, UpdateSourceTrigger=PropertyChanged}"

冗余的TwoWay模式可能导致绑定逻辑异常。


内容的提问来源于stack exchange,提问作者Siqueler

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 16:35:27