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

WPF中窗口2触发事件时如何更新窗口1的视图?

问题根源与解决办法

兄弟,你这问题的核心其实是两个窗口各自创建了独立的MainViewModel实例——相当于你在窗口2改了一份文档,窗口1打开的是另一份完全不同的文档,那视图当然不会更新啦!另外还有个小问题:你用List来存集合数据,它不会主动通知视图自己变了,得换成ObservableCollection才行。

具体哪里错了?

  1. 实例不共享:看你的代码,Scanner窗口和LoadingHistory窗口都各自new了一个MainViewModel,这俩是完全独立的对象。窗口2修改的是自己的ViewModel数据,窗口1绑定的那个ViewModel根本没收到任何更新,视图自然纹丝不动。
  2. 集合类型不对:LoadingHistoryTopView里的Paint、Bake这些集合如果是List<T>的话,就算你往里面加元素,视图也感知不到——因为List不支持集合变更通知,只有ObservableCollection才会在内容变化时主动告诉视图“我变了,快更新!”。

怎么改?

第一步:让两个窗口共享同一个ViewModel实例

最直接的办法就是在应用启动时创建一个全局的ViewModel,然后把它传递给两个窗口,确保它们绑定的是同一个对象。

修改LoadingHistory窗口的构造函数

把原来自己new ViewModel的代码改成接收外部传入的实例:

public partial class LoadingHistory : Window
{
    public List<LoadingHistoryModel> LoadhistoryVM = new List<LoadingHistoryModel>();
    public LoadingHistoryTopView LoadhistorytopVM = new LoadingHistoryTopView();
    public MainViewModel _MainViewModel;

    // 接收外部传来的共享ViewModel
    public LoadingHistory(MainViewModel sharedViewModel)
    {
        _MainViewModel = sharedViewModel;
        InitializeComponent();
        DataContext = _MainViewModel;
        PopulateHistory();
    }
}

修改Scanner窗口的构造函数

同样接收共享实例,并且用这个实例初始化窗口1:

public partial class Scanner : Window
{
    LoadCurrentBetween objMain = new LoadCurrentBetween();
    LoadingHistory objLoadHistory;
    MainViewModel _MainViewModel;
    LoadHistoryUC objLoad = new LoadHistoryUC();

    // 接收共享ViewModel
    public Scanner(MainViewModel sharedViewModel)
    {
        _MainViewModel = sharedViewModel;
        // 用同一个实例创建窗口1
        objLoadHistory = new LoadingHistory(_MainViewModel);
        DataContext = _MainViewModel;
        InitializeComponent();
    }

    private void PaintScan(object sender, RoutedEventArgs e)
    {
        // 插入数据库的代码保持不变
        DbOperations.InsertScanHistory(_MainViewModel.LoadCurrentViewModelData.Part, 
            Convert.ToInt32(_MainViewModel.LoadCurrentViewModelData.NoofHook), 
            2, _MainViewModel.LoadCurrentViewModelData.Date, 
            _MainViewModel.LoadCurrentViewModelData.Time);
        
        // 调用窗口1的方法更新共享ViewModel的数据
        objLoadHistory.PopulateHistory();
        MessageBox.Show("PaintScan Done");
    }
}

在应用启动时创建共享实例

比如在App.xaml.cs或者主窗口里初始化:

// 创建一个全局共享的ViewModel
var sharedVM = new MainViewModel();
// 打开两个窗口时都传入这个实例
var scannerWin = new Scanner(sharedVM);
var historyWin = new LoadingHistory(sharedVM);
scannerWin.Show();
historyWin.Show();

第二步:把集合换成ObservableCollection

修改LoadingHistoryTopView,把所有List换成ObservableCollection,并且确保这个类也实现INotifyPropertyChanged:

public class LoadingHistoryTopView : INotifyPropertyChanged
{
    // 用ObservableCollection替代List
    private ObservableCollection<PainttopView> _paint = new ObservableCollection<PainttopView>();
    public ObservableCollection<PainttopView> Paint
    {
        get => _paint;
        set
        {
            _paint = value;
            NotifyPropertyChanged(nameof(Paint));
        }
    }

    // 同理修改Bake和Cool集合
    private ObservableCollection<BaketopView> _bake = new ObservableCollection<BaketopView>();
    public ObservableCollection<BaketopView> Bake
    {
        get => _bake;
        set
        {
            _bake = value;
            NotifyPropertyChanged(nameof(Bake));
        }
    }

    private ObservableCollection<CooltopView> _cool = new ObservableCollection<CooltopView>();
    public ObservableCollection<CooltopView> Cool
    {
        get => _cool;
        set
        {
            _cool = value;
            NotifyPropertyChanged(nameof(Cool));
        }
    }

    // 其他属性也要正确触发PropertyChanged(示例)
    private int _hookNumber;
    public int HookNumber
    {
        get => _hookNumber;
        set
        {
            _hookNumber = value;
            NotifyPropertyChanged(nameof(HookNumber));
        }
    }

    // INotifyPropertyChanged实现
    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

第三步:优化PopulateHistory方法

在窗口1的这个方法里,不要每次都重新赋值集合,而是先清空再添加元素,避免绑定失效:

public void PopulateHistory()
{
    LoadhistoryVM = DbOperations.GetLoadHistory();
    if (LoadhistoryVM.Count > 0)
    {
        // 先清空现有集合,避免重复数据
        _MainViewModel.LoadHistoryTopActiveVM.Paint.Clear();
        _MainViewModel.LoadHistoryTopActiveVM.Bake.Clear();
        _MainViewModel.LoadHistoryTopActiveVM.Cool.Clear();
        _MainViewModel.LoadHistoryTopActiveVM.Hooks.Clear();

        for (var i = 0; i < LoadhistoryVM[0].GroupPartNumbers.Count(); i++)
        {
            switch (LoadhistoryVM[0].GroupPartNumbers[i].LinePosition)
            {
                case 2:
                    PainttopView paint = new PainttopView();
                    paint.Hookno = LoadhistoryVM[0].GroupPartNumbers[i].HookNumber;
                    paint.LinePosition = LoadhistoryVM[0].GroupPartNumbers[i].LinePosition;
                    paint.isEmpty = LoadhistoryVM[0].GroupPartNumbers[i].HookNumber == 0;
                    paint.ImgSource = paint.isEmpty ? "/Views/Image/RedStop.png" : "/Views/Image/Bluering.png";
                    _MainViewModel.LoadHistoryTopActiveVM.Paint.Add(paint);
                    break;
                // 其他case代码保持不变
            }
            _MainViewModel.LoadHistoryTopActiveVM.Hooks.Add(LoadhistoryVM[0].GroupPartNumbers[i].HookNumber);
            if (i == 0)
            {
                // 更新属性时确保触发PropertyChanged
                _MainViewModel.LoadHistoryTopActiveVM.HookNumber = LoadhistoryVM[0].GroupPartNumbers[i].HookNumber;
                _MainViewModel.LoadHistoryTopActiveVM.LinePosition = LoadhistoryVM[0].GroupPartNumbers[i].LinePosition;
                _MainViewModel.LoadHistoryTopActiveVM.PartNumber = LoadhistoryVM[0].GroupPartNumbers[i].PartNumber;
                _MainViewModel.LoadHistoryTopActiveVM.Workorder = LoadhistoryVM[0].GroupPartNumbers[i].Workorder;
                _MainViewModel.LoadHistoryTopActiveVM.Date = LoadhistoryVM[0].GroupPartNumbers[i].Date;
            }
        }
    }
    // 不需要重新设置DataContext,因为已经绑定了共享实例
    // DataContext = _MainViewModel;
}
最后再啰嗦两句
  • 多窗口共享数据的核心就是共用同一个ViewModel实例,别各自new各自的。
  • 集合一定要用ObservableCollection,不然视图不知道集合变了。
  • 所有绑定的属性都要正确实现INotifyPropertyChanged,包括子ViewModel里的属性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:41:57