WPF中ObservableCollection子项属性变更时TextBlock绑定不更新问题
问题根因
绑定不刷新由3处明确的代码错误导致,和total_dose是否实现set访问器无关:
- 你编写了集合变更监听方法
fractions_changed_CollectionChanged,但从未将其绑定到fx_list.CollectionChanged事件,集合增删元素时不会自动给子项挂载属性变更监听 - 子项
fx_dose值变化时,你错误触发了fx_list的属性变更通知,WPF绑定系统监听的是total_dose的变更信号,不会主动重新读取总和值 - 构造函数中手动添加的3个初始
fraction实例,没有挂载属性变更监听,哪怕事件绑定正确,初始项的数值修改也不会触发总和更新 - 额外隐患:
fraction类中fx_dose修改时联动变更的eq属性没有触发变更通知,后续绑定eq时也会出现不刷新的问题
修复方案
按以下步骤修改即可实现实时同步总和:
- 在
structure类构造函数中,初始化fx_list后立刻绑定集合变更事件,确保后续新增/删除的子项能自动挂载属性监听 - 子项
fx_dose变更、集合本身增删元素时,统一触发total_dose的属性变更通知,告知绑定系统重新读取计算后的总和值 - 移除
total_dose中无意义的空set块,计算属性仅保留get逻辑即可,只要正确触发变更通知就能正常刷新 - 补全
eq属性的变更通知逻辑,避免后续绑定出现问题
修复后完整代码
C# 后端代码
using System; using System.Linq; using System.Windows; using System.Collections.ObjectModel; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Collections.Specialized; namespace WpfApp2 { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); structure temp_struct = new structure("Bladder"); structure_info_list.ItemsSource = temp_struct.fx_list; this.DataContext = temp_struct; } } public class structure : INotifyPropertyChanged { public structure(string name) { this.name = name; // 初始化集合并绑定集合变更事件 fx_list = new ObservableCollection<fraction>(); fx_list.CollectionChanged += fractions_changed_CollectionChanged; fraction fx1 = new fraction(3); fraction fx2 = new fraction(4); fraction fx3 = new fraction(5); fx_list.Add(fx1); fx_list.Add(fx2); fx_list.Add(fx3); } private void fractions_changed_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.Action == NotifyCollectionChangedAction.Add) { foreach (var item in e.NewItems) { ((fraction)item).PropertyChanged += fx_Changed; } } else if (e.Action == NotifyCollectionChangedAction.Remove) { foreach (var item in e.OldItems) { ((fraction)item).PropertyChanged -= fx_Changed; } } // 集合增删后总和同步变化,触发刷新 OnPropertyChanged(nameof(total_dose)); } void fx_Changed(object sender, PropertyChangedEventArgs e) { // 子项剂量变更时,通知总和属性刷新 if (e.PropertyName == nameof(fraction.fx_dose)) { OnPropertyChanged(nameof(total_dose)); } } public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public string name { get; set; } public ObservableCollection<fraction> fx_list { get; set; } // 计算属性仅保留get,正确触发变更通知即可自动刷新 public int total_dose { get { return fx_list.Sum(x => x.fx_dose); } } } public class fraction : INotifyPropertyChanged { private int _fx_dose; public int fx_dose { get { return _fx_dose; } set { _fx_dose = value; calc_eq(); OnPropertyChanged(); // 联动变更的eq属性同步触发刷新通知 OnPropertyChanged(nameof(eq)); } } private int _eq; public int eq { get { return _eq; } set { _eq = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; public fraction(int fx_dose) { this.fx_dose = fx_dose; } public void calc_eq() { this.eq = this.fx_dose * 2; } private void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }
XAML 前端代码
<Window x:Class="WpfApp2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp2" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <StackPanel Margin="10"> <ItemsControl Name="structure_info_list"> <ItemsControl.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal" Margin="2"> <TextBlock Text="单次剂量:" VerticalAlignment="Center"/> <TextBox Text="{Binding Path=fx_dose, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="100"/> </StackPanel> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> <StackPanel Orientation="Horizontal" Margin="2 10 0 0"> <TextBlock Text="总剂量:" FontWeight="Bold"/> <TextBlock Text="{Binding Path=total_dose}" FontWeight="Bold" Foreground="Red"/> </StackPanel> </StackPanel> </Window>
修复后效果:页面加载时自动计算初始总和,修改任意输入框的剂量值、新增/删除集合中的剂量项,总剂量都会实时同步刷新,不需要额外编写手动赋值逻辑。
内容的提问来源于stack exchange,提问作者thatguy14
相关产品推荐
相关产品推荐

