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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 18:35:22