如何在WPF C#中使用数据绑定并解决数据源更新后控件未自动刷新的问题
嘿,我来帮你搞定这个WPF数据绑定的问题!你遇到的UI不更新问题,根源在于两个小细节没处理对,咱们一步步拆解解决:
问题出在哪?
你的代码里有两个核心原因导致DataGrid不更新:
- 直接赋值ItemsSource,没走数据绑定:你在
Window_Loaded里直接把dg.ItemsSource设为personList1.People的引用——这是一次性的赋值操作。当你在Refresh里给personList1.People重新赋值时,DataGrid还握着原来那个List的引用,根本不知道有新集合出现。 - List
不支持集合变更通知 :就算你解决了第一个问题,List<T>本身没有实现INotifyCollectionChanged接口,以后如果你对集合做增删元素的操作,UI也不会自动同步这些变化。
怎么改?
我们需要做两个关键调整,顺便优化你的绑定逻辑:
1. 把List换成ObservableCollection
ObservableCollection<T>是WPF专门为数据绑定设计的集合类型,内置了集合变更通知机制,增删改元素都会自动通知UI更新。
2. 用数据绑定关联DataGrid和ViewModel属性
别再直接给dg.ItemsSource赋值了,通过绑定让DataGrid监听ListOfPerson的People属性变化。这样当People重新赋值时,UI会收到通知并自动切换数据源。
修改后的完整代码
首先更新实体类:
using System.Collections.ObjectModel; using System.ComponentModel; using System.Runtime.CompilerServices; public class Person : INotifyPropertyChanged { private string name; public Person() { } public Person(string value) => name = value; public string PersonName { get => name; set { name = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged([CallerMemberName] string name = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } } public class ListOfPerson : INotifyPropertyChanged { // 替换List为ObservableCollection private ObservableCollection<Person> people = new ObservableCollection<Person>(); public ObservableCollection<Person> People { get => people; set { people = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged([CallerMemberName] string name = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } }
然后调整MainWindow的绑定逻辑:
public partial class MainWindow : Window, INotifyPropertyChanged { private ListOfPerson _personList1 = new ListOfPerson(); private ListOfPerson _personList2 = new ListOfPerson(); // 提供可绑定的属性,让UI能监听变化 public ListOfPerson PersonList1 { get => _personList1; set { _personList1 = value; OnPropertyChanged(); } } public MainWindow() { InitializeComponent(); // 把窗口自身设为DataContext,方便绑定 DataContext = this; } private void Window_Loaded(object sender, RoutedEventArgs e) { PersonList1.People.Add(new Person { PersonName = "test1" }); _personList2.People.Add(new Person { PersonName = "test2" }); dg.AutoGenerateColumns = false; // 配置列的绑定路径 var nameColumnBind = new Binding("PersonName") { Mode = BindingMode.TwoWay }; dg.Columns.Add(new DataGridTextColumn { Header = "Name", Binding = nameColumnBind }); // 用绑定设置ItemsSource,代替直接赋值 var itemsSourceBind = new Binding("PersonList1.People"); dg.SetBinding(DataGrid.ItemsSourceProperty, itemsSourceBind); } public void Refresh() { // 直接替换People集合,UI会自动更新 PersonList1.People = _personList2.People; // 如果只是更新集合内容而非替换整个集合,也可以这么写: // PersonList1.People.Clear(); // foreach(var person in _personList2.People) // PersonList1.People.Add(person); } private void btn_Refresh_Click(object sender, RoutedEventArgs e) => Refresh(); // 实现INotifyPropertyChanged,让PersonList1的变化能通知UI public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged([CallerMemberName] string name = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } }
额外小贴士
- 按照MVVM最佳实践,建议把
ListOfPerson这类ViewModel单独抽离出来,而不是让Window自己实现INotifyPropertyChanged——这样代码结构更清晰,也方便后续维护。 - 如果以后只是修改集合里的单个Person的
PersonName属性,因为你已经在Person类里实现了INotifyPropertyChanged,UI也会自动同步这些修改哦!
内容的提问来源于stack exchange,提问作者Maryam Heydari
相关产品推荐
相关产品推荐

