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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 10:18:23