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

C# WPF实现DataGrid行值变化时动态更新总金额文本框

动态计算DataGrid行Value总和并实时更新总金额的实现方案

核心思路是借助ObservableCollection<T>的集合变化通知能力,结合实体类的INotifyPropertyChanged事件,实时监听行数据的修改、新增和删除操作,自动计算所有行Value列的总和并同步到总金额文本框。

1. 完善实体类的INotifyPropertyChanged实现

确保业务实体完整实现接口,保证属性变更能通知到UI:

public class WorkItem : INotifyPropertyChanged
{
    private double _unitPrice;
    private double _hours;

    public double UnitPrice
    {
        get => _unitPrice;
        set
        {
            _unitPrice = value;
            OnPropertyChanged(nameof(UnitPrice));
            OnPropertyChanged(nameof(Value));
        }
    }

    public double Hours
    {
        get => _hours;
        set
        {
            _hours = value;
            OnPropertyChanged(nameof(Hours));
            OnPropertyChanged(nameof(Value));
        }
    }

    public double Value => UnitPrice * Hours;

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

注:Value属性可简化为只读计算属性,无需私有字段,因为它完全由UnitPrice和Hours推导而来。

2. ViewModel层实现总和计算逻辑

ViewModel需要维护DataGrid的数据源,并监听集合和元素的变更事件:

public class MainViewModel : INotifyPropertyChanged
{
    private ObservableCollection<WorkItem> _workItems;
    private double _totalAmount;

    public ObservableCollection<WorkItem> WorkItems
    {
        get => _workItems;
        set
        {
            if (_workItems != null)
            {
                _workItems.CollectionChanged -= WorkItems_CollectionChanged;
                UnsubscribeItemEvents(_workItems);
            }
            
            _workItems = value;
            
            if (_workItems != null)
            {
                _workItems.CollectionChanged += WorkItems_CollectionChanged;
                SubscribeItemEvents(_workItems);
            }
            
            CalculateTotal();
            OnPropertyChanged(nameof(WorkItems));
        }
    }

    public double TotalAmount
    {
        get => _totalAmount;
        set
        {
            _totalAmount = value;
            OnPropertyChanged(nameof(TotalAmount));
        }
    }

    public MainViewModel()
    {
        WorkItems = new ObservableCollection<WorkItem>();
    }

    private void WorkItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        switch (e.Action)
        {
            case NotifyCollectionChangedAction.Add:
                if (e.NewItems != null)
                    SubscribeItemEvents(e.NewItems.Cast<WorkItem>());
                break;
            case NotifyCollectionChangedAction.Remove:
                if (e.OldItems != null)
                    UnsubscribeItemEvents(e.OldItems.Cast<WorkItem>());
                break;
            case NotifyCollectionChangedAction.Reset:
                UnsubscribeItemEvents(_workItems);
                break;
        }
        CalculateTotal();
    }

    private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == nameof(WorkItem.Value))
            CalculateTotal();
    }

    private void SubscribeItemEvents(IEnumerable<WorkItem> items)
    {
        foreach (var item in items)
            item.PropertyChanged += Item_PropertyChanged;
    }

    private void UnsubscribeItemEvents(IEnumerable<WorkItem> items)
    {
        foreach (var item in items)
            item.PropertyChanged -= Item_PropertyChanged;
    }

    private void CalculateTotal()
    {
        TotalAmount = WorkItems.Sum(item => item.Value);
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

3. XAML绑定配置

在视图中绑定DataGrid和总金额文本框,确保输入时实时更新:

<!-- DataGrid配置 -->
<DataGrid ItemsSource="{Binding WorkItems}" 
          AutoGenerateColumns="False"
          CanUserDeleteRows="True">
    <DataGrid.Columns>
        <DataGridTextColumn Header="单价" 
                            Binding="{Binding UnitPrice, UpdateSourceTrigger=PropertyChanged}" />
        <DataGridTextColumn Header="时长" 
                            Binding="{Binding Hours, UpdateSourceTrigger=PropertyChanged}" />
        <DataGridTextColumn Header="金额" 
                            Binding="{Binding Value}" 
                            IsReadOnly="True" />
    </DataGrid.Columns>
</DataGrid>

<!-- 总金额显示 -->
<StackPanel Orientation="Horizontal" Margin="10 0">
    <TextBlock Text="总金额:" VerticalAlignment="Center"/>
    <TextBox Text="{Binding TotalAmount, Mode=OneWay}" 
             IsReadOnly="True" 
             Width="100" 
             Margin="5 0"/>
</StackPanel>

关键说明

  • ObservableCollection<T>:负责通知集合的增、删、重置操作,是实现行删除后自动扣减总和的核心
  • 元素事件订阅:给每个新增的WorkItem订阅PropertyChanged事件,监听Value属性变化,实现输入单价/时长时实时更新总和
  • UpdateSourceTrigger=PropertyChanged:确保输入框内容变化时立即更新源属性,触发后续的计算逻辑
  • 内存泄漏防护:移除元素时取消订阅其PropertyChanged事件,避免内存泄漏

内容的提问来源于stack exchange,提问作者Tharindu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 21:25:23