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

NET MAUI中MVVM命令修改double参数后视图未更新问题

购物车删除商品后总价不更新的修复方案

核心问题分析

你的代码中,删除商品后列表更新但总价不变化,主要有两个关键问题:

  1. ViewModel未实现INotifyPropertyChanged接口:虽然你定义了PropertyChanged事件和通知方法,但未显式继承接口,导致绑定系统无法监听Sum属性的变化。
  2. 手动维护总价的方式易遗漏场景:构造函数累加、删除时扣除的逻辑,无法覆盖商品数量修改(比如Stepper调整)的情况,且容易因引用或计算错误导致总价不同步。

修复步骤与代码示例

1. 让ViewModel实现INotifyPropertyChanged接口

修改ViewModel类定义,明确继承接口:

class BusketViewModel : INotifyPropertyChanged

2. 将Sum改为动态计算的只读属性

放弃手动维护总价,改为实时从集合中计算,避免同步错误:

public double Sum
{
    get 
    { 
        return ProductsInBasket?.Sum(item => item.product.Cost * item.quantityInBusket) ?? 0; 
    }
}

3. 监听集合与商品数量变化,触发总价更新

  • 监听ObservableCollection的CollectionChanged事件,在商品增删时通知Sum更新
  • 监听每个商品的数量变化,在用户通过Stepper调整数量时同步更新总价

4. 修复异步加载的死锁问题

替换GetFromJsonAsync(...).Result为异步加载,避免UI线程阻塞:

完整修复后的ViewModel代码

class BusketViewModel : INotifyPropertyChanged
{
    #region Fields
    private ObservableCollection<DTOProductAndQuantity> productsInBasket;
    private readonly HttpClient httpClient = new HttpClient();
    private Command<object> deleteProductCommand;

    public event PropertyChangedEventHandler PropertyChanged;
    #endregion

    #region Constructor
    public BusketViewModel()
    {
        deleteProductCommand = new Command<object>(DeleteProduct);
        LoadBasketAsync();
    }

    private async void LoadBasketAsync()
    {
        var productsFromHttp = await httpClient.GetFromJsonAsync<ObservableCollection<DTOProductAndQuantity>>("http://10.0.2.2:5125/api/Busket");
        ProductsInBasket = new ObservableCollection<DTOProductAndQuantity>(productsFromHttp);
        
        // 监听集合增删事件,更新总价
        ProductsInBasket.CollectionChanged += (s, e) => NotifyPropertyChanged(nameof(Sum));
        
        // 监听每个商品的数量变化,更新总价
        foreach (var item in ProductsInBasket)
        {
            if (item is INotifyPropertyChanged notifyItem)
            {
                notifyItem.PropertyChanged += (s, e) => 
                {
                    if (e.PropertyName == nameof(DTOProductAndQuantity.quantityInBusket))
                    {
                        NotifyPropertyChanged(nameof(Sum));
                    }
                };
            }
        }
    }
    
    private void DeleteProduct(object obj)
    {            
        if (obj is DTOProductAndQuantity productToDelete)
        {
            ProductsInBasket.Remove(productToDelete);
            // 无需手动修改Sum,CollectionChanged会自动触发更新
        }
    }
    #endregion

    #region Properties
    public ObservableCollection<DTOProductAndQuantity> ProductsInBasket
    {
        get { return productsInBasket; }
        set
        {
            if (productsInBasket != value)
            {
                productsInBasket = value;
                NotifyPropertyChanged();
            }
        }
    }

    public Command<object> DeleteProductCommand
    {
        get { return deleteProductCommand; }
        set { deleteProductCommand = value; }
    }

    public double Sum
    {
        get 
        { 
            return ProductsInBasket?.Sum(item => item.product.Cost * item.quantityInBusket) ?? 0; 
        }
    }
    #endregion

    protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

5. 让DTOProductAndQuantity实现INotifyPropertyChanged

确保数量变化时能通知ViewModel更新总价:

public class DTOProductAndQuantity : INotifyPropertyChanged
{
    private int quantityInBusket;
    public Product product { get; set; }

    public int quantityInBusket
    {
        get { return quantityInBusket; }
        set
        {
            if (quantityInBusket != value)
            {
                quantityInBusket = value;
                NotifyPropertyChanged();
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

修复说明

  1. 实现INotifyPropertyChanged接口后,绑定系统能正确监听属性变化,UI会在Sum更新时自动刷新。
  2. 动态计算Sum的方式,确保总价始终与购物车中的商品数量、价格保持一致,避免手动维护的错误。
  3. 监听集合和商品数量变化,覆盖了删除商品、调整数量等所有会影响总价的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 12:53:17