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

MAUI中嵌套StackLayout绑定InvHeader与对应InvItems的问题

MAUI 主详情页面关联数据显示问题

我正在MAUI中开发一个主详情页面,类似发票列表页面:展示多个发票表头,每个表头下方显示对应的发票明细项。

现有两个关联的SQL Server表(发票表头表和发票明细表),我已经把数据分别加载到ViewModel的两个列表中:InvHeaders(发票表头集合)和InvItems(发票明细集合)。

现在的需求是:滚动显示所有发票,每个发票表头下方只显示与之CustId匹配的发票明细项。目前的问题是,每个表头下方都会显示所有发票明细,无法过滤出对应CustId的项。

我尝试用转换器InvItemsForCustIdConverter来过滤,但始终无法把当前表头的CustId作为参数传递给转换器,参数一直是null。


当前代码

XAML页面

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage x:Name="parentView"
             xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:converters="clr-namespace:MauiClient"
             x:Class="MauiClient.Invoice"
             Title="Invoice">
    <ContentPage.Resources>
        <ResourceDictionary>
            <converters:InvItemsForCustIdConverter x:Key="InvItemsForCustIdConverter" />
        </ResourceDictionary>
    </ContentPage.Resources>

    <ScrollView>
        <StackLayout>
            <!-- Header section -->
            <Label Text="Hospitals" FontSize="Title" />
            <CollectionView ItemsSource="{Binding invHeaders}" BackgroundColor="Blue">
                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <StackLayout>
                            <Label Text="{Binding Company}" />
                            <Label Text="{Binding Addr1}" />
                            <Label Text="{Binding Phone}" />
                            <Label Text="{Binding CustId}" BackgroundColor="Red"  TextColor="White" />
                            <!-- Invoice items section -->
                            <Label Text="Tech Times" FontSize="Title" BackgroundColor="Yellow" TextColor="Black"/>
                            <StackLayout BindingContext="{Binding BindingContext, Source={x:Reference parentView}}" BackgroundColor="Green">
                                <StackLayout BindableLayout.ItemsSource="{Binding InvItems, Converter={StaticResource InvItemsForCustIdConverter}, ConverterParameter={Binding CustId}}">
                                    <BindableLayout.ItemTemplate>
                                        <DataTemplate>
                                            <StackLayout Orientation="Horizontal" Spacing="20">
                                                <Label Text="{Binding ItemId}" />
                                                <Label Text="{Binding CustId}" BackgroundColor="Red"  TextColor="White" />
                                            </StackLayout>
                                        </DataTemplate>
                                    </BindableLayout.ItemTemplate>
                                </StackLayout>
                            </StackLayout>
                        </StackLayout>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
        </StackLayout>
    </ScrollView>
</ContentPage>

ViewModel代码

public class InvoiceViewModel  {
        public List<InvHeader> InvHeaders { get; set; }
        public List<InvItem> InvItems { get; set; }
}

转换器代码

// 尝试过多种ConverterParameter写法,参数始终为null:
// <StackLayout BindableLayout.ItemsSource="{Binding InvItems, Converter={StaticResource InvItemsForCustIdConverter}, ConverterParameter={Binding InvHeader.CustId}}">
// <StackLayout BindableLayout.ItemsSource="{Binding InvItems, Converter={StaticResource InvItemsForCustIdConverter}, ConverterParameter={Binding CustId}}">
// <StackLayout BindableLayout.ItemsSource="{Binding InvItems, Converter={StaticResource InvItemsForCustIdConverter}, ConverterParameter={Binding CustId, Source={x:Reference parentView}, Path=InvHeader}}">

public class InvItemsForCustIdConverter : IValueConverter
{
  public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  {
      return value; // 返回全部明细时能显示,但无法过滤

      if (value is List<InvItem> invItems && parameter is string custId)
      {
          return invItems.Where(x => x.CustId == custId).ToList();
      }
      return null;
  }

  public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  {
      throw new NotImplementedException();
  }
}

问题核心

无法将当前CollectionView项(InvHeader)的CustId传递给转换器的ConverterParameter,导致无法按CustId过滤发票明细。


解决方案

方案1:修改数据模型,建立关联(推荐)

直接在InvHeader类中添加InvItems属性,加载数据时把对应明细关联到表头:

public class InvHeader
{
    // 原有属性
    public string Company { get; set; }
    public string Addr1 { get; set; }
    public string Phone { get; set; }
    public string CustId { get; set; }

    // 添加关联属性
    public List<InvItem> InvItems { get; set; }
}

加载数据时关联:

// 假设已加载invHeaders和invItems
foreach(var header in invHeaders)
{
    header.InvItems = invItems.Where(item => item.CustId == header.CustId).ToList();
}

然后修改XAML,直接绑定当前表头的InvItems,无需转换器:

<!-- 替换原有的明细部分 -->
<Label Text="Tech Times" FontSize="Title" BackgroundColor="Yellow" TextColor="Black"/>
<StackLayout BindableLayout.ItemsSource="{Binding InvItems}">
    <BindableLayout.ItemTemplate>
        <DataTemplate>
            <StackLayout Orientation="Horizontal" Spacing="20">
                <Label Text="{Binding ItemId}" />
                <Label Text="{Binding CustId}" BackgroundColor="Red"  TextColor="White" />
            </StackLayout>
        </DataTemplate>
    </BindableLayout.ItemTemplate>
</StackLayout>

方案2:用MultiBinding传递多个值(不修改模型)

如果不想修改数据模型,可以用MultiBinding把InvItems和当前CustId一起传给转换器:

  1. 创建多值转换器:
public class InvItemsForCustIdMultiConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if(values.Length == 2 && values[0] is List<InvItem> invItems && values[1] is string custId)
        {
            return invItems.Where(x => x.CustId == custId).ToList();
        }
        return null;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
  1. 在XAML资源中添加转换器:
<converters:InvItemsForCustIdMultiConverter x:Key="InvItemsForCustIdMultiConverter" />
  1. 修改明细部分的绑定:
<Label Text="Tech Times" FontSize="Title" BackgroundColor="Yellow" TextColor="Black"/>
<StackLayout>
    <StackLayout.BindableLayout.ItemsSource>
        <MultiBinding Converter="{StaticResource InvItemsForCustIdMultiConverter}">
            <Binding Path="BindingContext.InvItems" Source="{x:Reference parentView}" />
            <Binding Path="CustId" /> <!-- 这里绑定当前InvHeader的CustId -->
        </MultiBinding>
    </StackLayout.BindableLayout.ItemsSource>
    <BindableLayout.ItemTemplate>
        <DataTemplate>
            <StackLayout Orientation="Horizontal" Spacing="20">
                <Label Text="{Binding ItemId}" />
                <Label Text="{Binding CustId}" BackgroundColor="Red"  TextColor="White" />
            </StackLayout>
        </DataTemplate>
    </BindableLayout.ItemTemplate>
</StackLayout>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 18:47:14