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

如何将CollectionView中Stepper值>0的Addon存入Booking的ObservableCollection

问题描述

我正在开发预订结账页面的Addon添加功能,通过CollectionView展示当前可预订办公场地对应的Addon,每个Addon项包含Stepper控件用于选择数量。需求是在ViewModel的SaveBooking方法中,遍历CollectionView的每个DataTemplate项,当Stepper值大于0时,将该Addon的ImgName、Name、Price及Stepper值(数量)添加到Booking模型的BookedAddons(ObservableCollection)中。目前无法获取每个项的StepperValue,求实现方案。


相关代码

BookingInfo.xaml

<CollectionView x:Name="AddonSelection" ItemsSource="{Binding OfficeAddons}" SelectionMode="None">
                <CollectionView.EmptyView>
                    <Label Text="No Addons for this Office" TextColor="Gray" HorizontalOptions="Center" VerticalOptions="Center"/>
                </CollectionView.EmptyView>
                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <StackLayout Spacing="10" Orientation="Vertical" Padding="10, 10, 10, 10">
                            <Image Source="{Binding ImgName}" Aspect="AspectFill" HorizontalOptions="FillAndExpand" />
                            <StackLayout Orientation="Horizontal">
                                <Label Text="{Binding Name}" FontSize="Micro"/>
                                <Label Text="{Binding Price}" FontSize="Micro" FontAttributes="Bold"/>
                            </StackLayout>
                            <StackLayout Orientation="Vertical" HorizontalOptions="Center">
                                <Label x:Name="AddonQuantity" Text="{Binding SelectedQuantity}"/>
                                <Stepper x:Name="AddonQuantityStepper" Minimum="0" Maximum="{Binding Quantity}" Increment="1" Value="{Binding StepperValue}" HorizontalOptions="Center" />
                            </StackLayout>
                        </StackLayout>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>

BookingInfoVM.cs

public int SaveBooking()
    {
        int addstatus = 0;

        double numhours = CalculateBookingHourLenght();
        bool isActive = IsBookingActive();

        Models.Booking newbooking = new Models.Booking();
        ...

        // Addons
        

        foreach (Models.Addon OfficeAddon in OfficeAddons)
            // foreach (StackLayout Data in CollectView:AddonSelection)
        {
            // if steppervalue >=1 then ...
            newbooking.BookedAddons.Add(new Models.Addon
            {
                ImgName = OfficeAddon.ImgName,
                Name = OfficeAddon.Name,
                Price = OfficeAddon.Price,
                Quantity = StepperValue //Stuck
            });
        }
        globalref.TempBooking = newbooking;

        //addstatus = DBInstance.AddBooking(newbooking);

        return addstatus;
    }

Booking.cs

public class Booking
{
    [PrimaryKey, AutoIncrement]
    public int BID { get; set; }
    public DateTime Start_datetime { get; set; }
    //public TimeSpan Start_time { get; set; }
    public DateTime End_datetime { get; set; }
    //public TimeSpan End_time { get; set; }
    public bool isActive { get; set; }
    public double Total_hours { get; set; }
    public int NumGuests { get; set; }
    public string Activity { get; set; }
    public string TimePeriod { get; set; }
    //Payment



    // Foregin key to Booked Office
    public int OID { get; set; }
    public int HID { get; set; }
    public string OName { get; set; }
    public string OLocation { get; set; }

    
    // list of booked selected addons
    public ObservableCollection<Models.Addon> BookedAddons { get; set; }

    //public double TotalAddonPrice { get; set; }

    // Foregin key to Guest User
    public int UID { get; set; }
    public string GName { get; set; }


    public double OfficePrice { get; set; } // Office Hourly * Total_hours
    public double ServiceFee { get; set; } // set equal to (addon price + office price) * 0.15 
    public double FinalPrice { get; set; } // equal to office + addon + service 

}

Addon.cs

public class Addon
{
    [PrimaryKey, AutoIncrement]
    public int AID { get; set; }
    [Unique]
    public string Name { get; set; }
    public int Quantity { get; set; }
    public double Price { get; set; }
    public string ImgName { get; set; }

    // link to Office by ID
    public int OID { get; set; }
}

解决方案

核心思路是把Stepper的选择值直接绑定到Addon模型的属性上,让UI和数据双向同步,ViewModel不需要操作UI元素,直接从数据集合里就能拿到选中数量。

1. 给Addon模型添加选中数量属性并实现通知

在Addon类里新增SelectedQuantity属性,同时实现INotifyPropertyChanged接口,确保UI变更能同步到数据:

using System.ComponentModel;
using System.Runtime.CompilerServices;

public class Addon : INotifyPropertyChanged
{
    [PrimaryKey, AutoIncrement]
    public int AID { get; set; }
    [Unique]
    public string Name { get; set; }
    public int Quantity { get; set; }
    public double Price { get; set; }
    public string ImgName { get; set; }
    public int OID { get; set; }

    private int _selectedQuantity;
    public int SelectedQuantity
    {
        get => _selectedQuantity;
        set
        {
            if (_selectedQuantity != value)
            {
                _selectedQuantity = value;
                OnPropertyChanged();
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2. 调整XAML中的Stepper绑定

把Stepper的Value绑定到新增的SelectedQuantity,并显式声明双向绑定(确保UI操作能同步到模型):

<StackLayout Orientation="Vertical" HorizontalOptions="Center">
    <Label Text="{Binding SelectedQuantity}"/>
    <Stepper x:Name="AddonQuantityStepper" 
             Minimum="0" 
             Maximum="{Binding Quantity}" 
             Increment="1" 
             Value="{Binding SelectedQuantity, Mode=TwoWay}" 
             HorizontalOptions="Center" />
</StackLayout>

3. 修改SaveBooking方法逻辑

现在可以直接遍历OfficeAddons集合,筛选出选中数量大于0的Addon,添加到BookedAddons中:

public int SaveBooking()
{
    int addstatus = 0;

    double numhours = CalculateBookingHourLenght();
    bool isActive = IsBookingActive();

    Models.Booking newbooking = new Models.Booking();
    // 初始化集合,避免空引用异常
    newbooking.BookedAddons = new ObservableCollection<Models.Addon>();
    ...

    // 处理选中的Addons
    foreach (Models.Addon officeAddon in OfficeAddons)
    {
        if (officeAddon.SelectedQuantity > 0)
        {
            newbooking.BookedAddons.Add(new Models.Addon
            {
                ImgName = officeAddon.ImgName,
                Name = officeAddon.Name,
                Price = officeAddon.Price,
                Quantity = officeAddon.SelectedQuantity
            });
        }
    }

    globalref.TempBooking = newbooking;

    //addstatus = DBInstance.AddBooking(newbooking);

    return addstatus;
}

4. 初始化时重置选中数量

在ViewModel加载OfficeAddons的时候,记得把每个Addon的SelectedQuantity设为0,避免残留之前的选择状态:

public ObservableCollection<Models.Addon> OfficeAddons { get; set; }

public void LoadOfficeAddons(int officeId)
{
    // 从数据库获取对应办公场地的Addons
    var addons = DBInstance.GetAddonsByOfficeId(officeId);
    OfficeAddons = new ObservableCollection<Models.Addon>(addons);
    
    // 重置选中数量为0
    foreach (var addon in OfficeAddons)
    {
        addon.SelectedQuantity = 0;
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 23:15:50