WPF视图切换数据丢失求助:添加人员后DataGrid无数据
WPF视图切换时数据丢失问题解决方案
问题描述
开发WPF项目时,主窗口通过左侧按钮切换右侧ContentControl的视图:
- 一个视图是添加人员表单,绑定
ObservableCollection<PersonModel>的DataGrid能正常显示新增数据 - 切换到展示人员的DataGrid视图时,仅显示表头,无人员数据
核心原因
- ViewModel实例独立:每次切换视图时,
NavigationViewModel都会创建新的AddPeopleViewModel和DisplayPeopleViewModel实例,两个实例的People集合完全分离,新增数据只存在于当前AddPeopleViewModel中,展示视图的新实例集合为空。 - UserControl硬编码DataContext:两个视图内部直接设置
DataContext为新ViewModel实例,覆盖了ContentControl传递的ViewModel,导致绑定的是独立的局部实例。
修复步骤
1. 移除UserControl内部的DataContext设置
分别修改AddPeopleView和DisplayPeopleView的XAML,删除<UserControl.DataContext>节点,让视图继承ContentControl传递的ViewModel:
修改后的AddPeopleView
<UserControl x:Class="SwitchViewsDemo2.Views.AddPeopleView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:vm="clr-namespace:SwitchViewsDemo2.ViewModels" mc:Ignorable="d" FontSize="28" d:DesignHeight="450" d:DesignWidth="800"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="1*"/> <RowDefinition Height="2*"/> </Grid.RowDefinitions> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <TextBlock Text="Add People" /> <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center"> <TextBlock Text="First Name" /> <TextBox Text="{Binding FirstName}"/> </StackPanel> <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Column="1"> <TextBlock Text="Last Name" /> <TextBox Text="{Binding LastName}"/> </StackPanel> </Grid> <StackPanel Grid.Row="1"> <Button Content="Add Person" Command="{Binding AddPersonCommand}" Height="40" Width="200" VerticalAlignment="Top"/> <DataGrid ItemsSource="{Binding People}"/> </StackPanel> </Grid> </UserControl>
修改后的DisplayPeopleView
<UserControl x:Class="SwitchViewsDemo2.Views.DisplayPeopleView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:vm="clr-namespace:SwitchViewsDemo2.ViewModels" mc:Ignorable="d" FontSize="28" d:DesignHeight="450" d:DesignWidth="800"> <Grid> <StackPanel> <TextBlock Text="Display People"/> <DataGrid ItemsSource="{Binding People}"/> </StackPanel> </Grid> </UserControl>
2. 创建共享数据源
新建PeopleRepository类管理全局共享的人员集合:
using SwitchViewsDemo2.Models; using System.Collections.ObjectModel; namespace SwitchViewsDemo2.Models { public class PeopleRepository { public ObservableCollection<PersonModel> People { get; } = new ObservableCollection<PersonModel>(); } }
3. 修改ViewModelBase,移除独立集合
using System.ComponentModel; using System.Runtime.CompilerServices; namespace SwitchViewsDemo2.Utilities { public class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler? PropertyChanged; public void OnPropertyChanged([CallerMemberName] string propName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); } }
4. 更新NavigationViewModel,注入共享数据源
using SwitchViewsDemo2.Models; using SwitchViewsDemo2.Utilities; using System.Windows.Input; namespace SwitchViewsDemo2.ViewModels { public class NavigationViewModel : ViewModelBase { private readonly PeopleRepository _peopleRepo; private object _currentView; public object CurrentView { get { return _currentView; } set { _currentView = value; OnPropertyChanged(); } } public ICommand GoToAddPeopleCommand { get; set; } public ICommand GoToDisplayPeopleCommand { get; set; } private void AddPeople(object obj) => CurrentView = new AddPeopleViewModel(_peopleRepo); private void DisplayPeople(object obj) => CurrentView = new DisplayPeopleViewModel(_peopleRepo); public NavigationViewModel() { _peopleRepo = new PeopleRepository(); GoToAddPeopleCommand = new RelayCommand(AddPeople); GoToDisplayPeopleCommand = new RelayCommand(DisplayPeople); CurrentView = new AddPeopleViewModel(_peopleRepo); } } }
5. 更新AddPeopleViewModel,绑定共享集合
using SwitchViewsDemo2.Models; using SwitchViewsDemo2.Utilities; using System.Collections.ObjectModel; namespace SwitchViewsDemo2.ViewModels { public class AddPeopleViewModel : ViewModelBase { private readonly PeopleRepository _peopleRepo; private string _firstName; public string FirstName { get { return _firstName; } set { _firstName = value; OnPropertyChanged(); } } private string _lastName; public string LastName { get { return _lastName; } set { _lastName = value; OnPropertyChanged(); } } public ObservableCollection<PersonModel> People => _peopleRepo.People; public ButtonCommand AddPersonCommand { get; set; } public void AddPerson() { PersonModel p = new PersonModel() { FirstName = FirstName, LastName = LastName }; FirstName = string.Empty; LastName = string.Empty; People.Add(p); } public AddPeopleViewModel(PeopleRepository peopleRepo) { _peopleRepo = peopleRepo; AddPersonCommand = new ButtonCommand(AddPerson); } } }
6. 更新DisplayPeopleViewModel,绑定共享集合
using SwitchViewsDemo2.Models; using SwitchViewsDemo2.Utilities; using System.Collections.ObjectModel; namespace SwitchViewsDemo2.ViewModels { public class DisplayPeopleViewModel : ViewModelBase { private readonly PeopleRepository _peopleRepo; public ObservableCollection<PersonModel> People => _peopleRepo.People; public DisplayPeopleViewModel(PeopleRepository peopleRepo) { _peopleRepo = peopleRepo; } } }
修复效果
现在切换视图时,两个ViewModel共享同一个PeopleRepository中的ObservableCollection,新增人员后切换到展示视图,DataGrid会正常显示所有已添加的数据。
内容的提问来源于stack exchange,提问作者Ricman1029
相关产品推荐
相关产品推荐

