WPF重新加载后DataGrid不显示ObservableCollection的问题排查
首次加载发票数据时,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

