CommunityToolkit.WinUI DataGrid绑定ObservableCollection后不更新问题
我有一个包含“全部”“活跃”“非活跃”三个筛选选项的下拉框,切换选中值时会触发事件,调整ViewModel中绑定到用户展示DataGrid的ObservableCollection类型属性ProjectDbUsers。调试时发现ProjectDbUsers属性已成功变更,但DataGrid并未刷新以匹配修改后的集合。
环境说明:
- 主UI项目使用
CommunityToolkit.WinUI.Controls.DataGrid包 - 包含ViewModel的业务层项目使用
CommunityToolkit.Mvvm包
相关代码:
管理用户页面XAML中的ComboBox与DataGrid
<ComboBox x:Name="BasicUserFilter" Grid.Row="0" Grid.Column="1" Height="30" Width="Auto" Margin="20,10,10,10" ItemsSource="{x:Bind ViewModel.Filters, Mode=OneWay}" SelectedItem="{x:Bind ViewModel.SelectedFilter, Mode=TwoWay}" SelectionChanged="BasicUserFilter_SelectionChanged"/> <controls:DataGrid x:Name="dataGrid1" Grid.Row="2" Height="600" Margin="12" AutoGenerateColumns="False" ItemsSource="{x:Bind ViewModel.ProjectDbUsers, Mode=OneWay}"> <controls:DataGrid.Columns> <controls:DataGridTextColumn Header="Name" Width="250" Binding="{Binding UserAddisplayName}" FontSize="14" /> ... </controls:DataGrid.Columns> </controls:DataGrid>
下拉框选择变更事件后台代码
private void BasicUserFilter_SelectionChanged(object sender, SelectionChangedEventArgs e) { ViewModel.UpdateGridBasedOnFilter(); }
ViewModel类中的属性定义与筛选方法
[ObservableProperty] private string _selectedFilter; public ObservableCollection<string> Filters { get; } = new ObservableCollection<string>(new List<string>() { "All", "Active", "Inactive" }); public ObservableCollection<UserAd> ProjectDbUsers { get; private set; } public void UpdateGridBasedOnFilter() { using (UnitOfWorkDbGlobal unitOfWorkDbGlobal = new(new MyDBContext())) { List<UserAd> users = new(); switch (SelectedFilter) { case "All": users = unitOfWorkDbGlobal.UserAds.GetAllUsers().ToList(); break; case "Active": users = unitOfWorkDbGlobal.UserAds.GetAllActiveUsers().ToList(); break; case "Inactive": users = unitOfWorkDbGlobal.UserAds.GetAllInactiveUsers().ToList(); break; } ProjectDbUsers = new ObservableCollection<UserAd>(users); } }
请问需要补充什么配置或代码,才能让DataGrid在ProjectDbUsers变更时同步更新?
问题核心是ProjectDbUsers属性重新赋值时未触发属性变更通知,DataGrid无法感知到属性已替换为新的ObservableCollection实例。结合你使用的CommunityToolkit.Mvvm包,提供以下几种解决方式:
方式一:使用[ObservableProperty]特性(推荐)
将ProjectDbUsers的手动定义改为MVVM Toolkit的自动实现,它会自动生成属性变更通知逻辑:
// 替换原来的手动属性定义 [ObservableProperty] private ObservableCollection<UserAd> _projectDbUsers = new(); // 初始化空集合
在UpdateGridBasedOnFilter方法中直接给生成的属性赋值(Toolkit会自动生成首字母大写的ProjectDbUsers属性):
public void UpdateGridBasedOnFilter() { using (UnitOfWorkDbGlobal unitOfWorkDbGlobal = new(new MyDBContext())) { List<UserAd> users = new(); switch (SelectedFilter) { case "All": users = unitOfWorkDbGlobal.UserAds.GetAllUsers().ToList(); break; case "Active": users = unitOfWorkDbGlobal.UserAds.GetAllActiveUsers().ToList(); break; case "Inactive": users = unitOfWorkDbGlobal.UserAds.GetAllInactiveUsers().ToList(); break; } ProjectDbUsers = new ObservableCollection<UserAd>(users); } }
方式二:手动触发属性变更通知
如果不想使用[ObservableProperty],确保ViewModel继承ObservableObject(来自CommunityToolkit.Mvvm),并在ProjectDbUsers的setter中调用SetProperty触发通知:
public class YourViewModel : ObservableObject { private ObservableCollection<UserAd> _projectDbUsers; public ObservableCollection<UserAd> ProjectDbUsers { get => _projectDbUsers; private set => SetProperty(ref _projectDbUsers, value); } // 其余代码保持不变 }
额外优化:复用现有集合(可选)
如果不想每次筛选都创建新的ObservableCollection,可以清空现有集合再添加新数据,利用ObservableCollection自身的集合变更通知:
public void UpdateGridBasedOnFilter() { using (UnitOfWorkDbGlobal unitOfWorkDbGlobal = new(new MyDBContext())) { List<UserAd> users = new(); switch (SelectedFilter) { case "All": users = unitOfWorkDbGlobal.UserAds.GetAllUsers().ToList(); break; case "Active": users = unitOfWorkDbGlobal.UserAds.GetAllActiveUsers().ToList(); break; case "Inactive": users = unitOfWorkDbGlobal.UserAds.GetAllInactiveUsers().ToList(); break; } ProjectDbUsers.Clear(); foreach (var user in users) { ProjectDbUsers.Add(user); } } }
这种方式下,只要集合内容变化,DataGrid就会更新,无需触发属性变更通知(前提是ProjectDbUsers初始化后未被重新赋值)。
内容的提问来源于stack exchange,提问作者E. A. Bagby

