WPF中子类绑定父类属性失效问题的解决方案
问题场景
Scoda类继承自Car类,Car类包含Color属性,Scoda类包含Speed属性。主窗口的DataGrid绑定到Car类型的ObservableCollection列表,点击按钮修改列表中对象的Color和Speed属性时,Speed属性能正常更新,但Color属性无变化。
问题根源
你的Scoda类重复实现了INotifyPropertyChanged接口,并且重新定义了PropertyChanged事件和OnPropertyChanged方法。WPF绑定的是子类实例的PropertyChanged事件,但父类Car中Color属性变更时触发的是父类自己的PropertyChanged事件,这个事件并没有被WPF监听,所以属性变更通知无法传递到UI层。
解决方案
子类不需要重复实现INotifyPropertyChanged接口,直接继承父类的实现即可。如果需要在子类中扩展属性变更逻辑,只需要重写父类的OnPropertyChanged虚方法,而不是重新定义整个事件和方法。
修改后的代码
Car.cs(无需修改)
public class Car : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private string color { get; set; } public string Color { get { return color; } set { color = value; OnPropertyChanged(nameof(Color)); } } protected virtual void OnPropertyChanged(string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
Scoda.cs(关键修改)
移除重复的INotifyPropertyChanged实现,直接使用父类的事件和方法,若需要扩展则重写OnPropertyChanged:
public class Scoda : Car { public Scoda(int speed) { this.Speed = speed; } private int speed { get; set; } public int Speed { get { return speed; } set { speed = value; OnPropertyChanged(nameof(Speed)); } } // 可选:如果子类需要额外的属性变更逻辑,重写父类方法即可 protected override void OnPropertyChanged(string propertyName = null) { // 先执行父类的通知逻辑 base.OnPropertyChanged(propertyName); // 这里可以添加子类自己的逻辑 } }
MainWindow.xaml.cs(优化循环逻辑)
原循环中直接遍历Scoda可能会抛出类型转换异常,建议用OfType<Scoda>()筛选:
public partial class MainWindow : Window, INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private ObservableCollection<Car> carList { get; set; } public ObservableCollection<Car> CarList { get { return carList; } set { carList = value; OnPropertyChanged(nameof(CarList)); } } public MainWindow() { InitializeComponent(); DataContext = this; CarList = new ObservableCollection<Car>(); Car car = new Scoda(150); CarList.Add(car); } private void Button_Click(object sender, RoutedEventArgs e) { // 用OfType筛选出Scoda类型的对象,避免类型转换错误 foreach (Scoda car in CarList.OfType<Scoda>()) { car.Speed = 120; car.Color = "Red"; } } protected virtual void OnPropertyChanged(string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
原理说明
当子类继承自已经实现INotifyPropertyChanged的父类时,子类会自动继承该接口的实现。父类的OnPropertyChanged方法是虚方法,子类可以重写它来扩展逻辑,但不需要重新声明PropertyChanged事件。这样无论父类还是子类的属性变更,都会触发同一个PropertyChanged事件,WPF能正确接收到通知并更新UI。
内容的提问来源于stack exchange,提问作者şahin

