WPF弹窗关闭后如何更新主窗口UserControl的DataGrid
问题描述
我开发的WPF应用中,主窗口包含多个UserControl,其中一个UserControl内有DataGrid。用户选中DataGrid行后会弹出窗口修改数据并保存到本地SQLite数据库,但弹窗关闭后,SQLite数据已更新,DataGrid却未刷新。调试时可见数据查询方法和OnPropertyChanged已调用,但界面无变化。请问如何在弹窗关闭时更新主窗口的UserControl?
主窗口UserControl的DataGrid代码
<DataGrid Name="datagrid" SelectedItem="{Binding SelectedRow, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding Path=PendingResults, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" AutoGenerateColumns="False" CanUserAddRows="False" Height="450" Margin="5" SelectionMode="Single" SelectionUnit="FullRow" IsReadOnly="True" AlternatingRowBackground="AliceBlue" CanUserSortColumns="True"> <DataGrid.Columns> <DataGridTextColumn Header="Id" Binding="{Binding ID}" /> <DataGridTextColumn Header="Client" Binding="{Binding Client}" /> <DataGridTextColumn Header="Name" Binding="{Binding Name}" /> <DataGridTextColumn Header="Type" Binding="{Binding TestType}" /> <DataGridTemplateColumn> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Button Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=DataContext.LoadCommand}">Finish</Button> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> <DataGridTemplateColumn> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Button Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=DataContext.DeleteCommand}">Delete</Button> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid>
主窗口UserControl的ViewModel代码
internal class PendingTestsViewModel : ObservableObject { public List<SavedTestResults> _pendingResults; public SavedTestResults _selectedRow { get; set; } public List<SavedTestResults> PendingResults { get { return _pendingResults; } set { _pendingResults = value; OnPropertyChanged("PendingResults"); } } public SavedTestResults SelectedRow { get { return _selectedRow; } set { _selectedRow = value; OnPropertyChanged(); } } public RelayCommand LoadMeterCommand { get; set; } public RelayCommand RefreshPendingListCommand { get; set; } public RelayCommand DeleteMeterCommand { get; set; } public PendingTestsViewModel() { LoadMeterCommand = new RelayCommand(o => TestSelectedMeter()); DeleteMeterCommand = new RelayCommand(o => DeletePendingTest()); RefreshPendingListCommand = new RelayCommand(o => PendingSearchResults()); PendingSearchResults(); } private void PendingSearchResults() { using (SQLiteConnection con = new SQLiteConnection("data source=Database.sqlite")) { using (SQLiteCommand com = new SQLiteCommand(con)) { StringBuilder query = new StringBuilder(); query.Append(@"Query Test is here"); com.CommandText = query.ToString(); con.Open(); try { List<SavedTestResults> Results = new List<SavedTestResults>(); SQLiteDataReader dr = com.ExecuteReader(); while (dr.Read()) { SavedResults results = new SavedResults(); //results are added here Results.Add(results); } PendingResults = Results; //Update ObservableCollection } catch (Exception ex) { MessageBox.Show(ex.Message); } con.Close(); } } } }
ObservableObject类代码
internal class ObservableObject : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string name = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } }
弹窗中调用主窗口UserControl的方法
public void RefreshPending() { PendingTests pendingTests = new PendingTests(); }
解决方案
1. 替换List为ObservableCollection
List<T>不支持集合内部元素变化的自动通知,改用ObservableCollection<T>(自带INotifyCollectionChanged接口),能确保集合增删改时界面实时响应:
// 修改ViewModel中的集合类型 public ObservableCollection<SavedTestResults> _pendingResults; public ObservableCollection<SavedTestResults> PendingResults { get { return _pendingResults; } set { _pendingResults = value; OnPropertyChanged(nameof(PendingResults)); } } // 构造函数初始化集合 public PendingTestsViewModel() { _pendingResults = new ObservableCollection<SavedTestResults>(); // 其他代码不变 } // 刷新数据时,建议清空原有集合再添加新数据(或直接赋值新的ObservableCollection) private void PendingSearchResults() { // ... 数据库查询逻辑 try { List<SavedTestResults> Results = new List<SavedTestResults>(); // ... 读取数据到Results PendingResults.Clear(); foreach(var item in Results) { PendingResults.Add(item); } // 或者直接赋值:PendingResults = new ObservableCollection<SavedTestResults>(Results); } // ... 异常处理 }
2. 修复弹窗刷新逻辑
当前RefreshPending方法新建了PendingTests实例,和主窗口中已存在的UserControl无关,需通过以下方式实现有效刷新:
方法A:弹窗关闭后主动调用ViewModel刷新
打开弹窗时,在弹窗关闭后直接触发主ViewModel的刷新方法:
// 主窗口中打开弹窗的代码 var editWindow = new YourEditWindow(); if(editWindow.ShowDialog() == true) { // 弹窗关闭后调用数据查询方法刷新界面 pendingTestsViewModel.PendingSearchResults(); }
方法B:通过事件通知刷新
在弹窗中定义事件,主窗口订阅事件,弹窗保存数据后触发事件通知刷新:
// 弹窗类中定义事件 public event Action OnDataUpdated; // 弹窗保存数据并关闭的方法 private void SaveAndClose() { // 保存数据到SQLite的逻辑 OnDataUpdated?.Invoke(); this.Close(); } // 主窗口中打开弹窗时订阅事件 var editWindow = new YourEditWindow(); editWindow.OnDataUpdated += () => { pendingTestsViewModel.PendingSearchResults(); }; editWindow.ShowDialog();
3. 确保数据模型实现INotifyPropertyChanged
如果修改的是DataGrid已有行的属性值,SavedTestResults类需继承ObservableObject,确保单个属性变化时界面能收到通知:
internal class SavedTestResults : ObservableObject { private int _id; public int ID { get => _id; set { _id = value; OnPropertyChanged(); } } // 其他属性(Client、Name等)按相同方式实现 }
内容的提问来源于stack exchange,提问作者GoForIt
相关产品推荐
相关产品推荐

