XAML 嵌套集合视图或在集合视图中显示嵌套数据

q5lcpyga  于 2023-08-01  发布在  其他
关注(0)|答案(2)|浏览(109)

我试图避免不好的做法,不添加集合视图内的集合视图显示嵌套的数据,我有一个类

public partial class Items
   {
        public int itemNumber { get; set; }
        public string itemdescr{ get; set; }
        public List<Items> Child { get; set; }
    }

字符串
我的集合视图看起来是这样的

<CollectionView x:Name="CollectionViewBoM" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="9" ItemsSource="{Binding Data}">
                    <CollectionView.ItemTemplate>
                        <DataTemplate >
                            <mct:Expander >
                                <mct:Expander.Header>
                                    <Grid HeightRequest="45" MaximumHeightRequest="90" ColumnSpacing="1" RowSpacing="2">
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="240"/>
                                            <ColumnDefinition Width="*"/>
                                        </Grid.ColumnDefinitions>
                                        <BoxView Grid.Column="0" Style="{DynamicResource ContentBoxView}"/>
                                        <BoxView Grid.Column="1" Style="{DynamicResource ContentBoxView}"/>
                                        <Label TextColor="{DynamicResource SecondaryTextColor}" Grid.Column="0" Text="{Binding itemNumber}" Style="{DynamicResource ContentLabel}"/>
                                        <Label TextColor="{DynamicResource SecondaryTextColor}" Grid.Column="1" Text="{Binding Description}" Style="{DynamicResource ContentLabel}"/>
                                    </Grid>
                                </mct:Expander.Header>
                                <mct:Expander.Content x:Name="CollectionViewChild">
                                    <StackLayout BindableLayout.ItemsSource="{Binding Child}">
                                        <BindableLayout.ItemTemplate>
                                            <DataTemplate>
                                                <HorizontalStackLayout>
                                                    <Label Text="{Binding itemNumber}" />
                                                    <Label Text="{Binding itemdescr}"  Margin="10,0,0,0"/>
                                                </HorizontalStackLayout>
                                            </DataTemplate>
                                        </BindableLayout.ItemTemplate>
                                    </StackLayout>
                                </mct:Expander.Content>
                            </mct:Expander>
                        </DataTemplate>
                    </CollectionView.ItemTemplate>
                </CollectionView>


我绑定到视图模型,但我能够看到数据,但不能看到子数据。我是否错误地使用了BindableLayout.ItemsSource?

[ObservableProperty]
        public List<Items> data;

zujrkrfu

zujrkrfu1#

您可以重新检查是否可以正确获取内部列表数据(Child)。
根据你的代码,我做了一个演示来实现这个功能,它可以正常工作。
可以参考以下代码:

public partial class MyViewModel:ObservableObject 
{
    [ObservableProperty]
    public List<Items> data;

    public MyViewModel()
    {
        List<Items> Childs = new List<Items>();

        Childs.Add(new Items { itemNumber = 01 - 1, itemdescr = "desc-01-1" });
        Childs.Add(new Items { itemNumber = 02 - 1, itemdescr = "desc-02-1" });
        Childs.Add(new Items { itemNumber = 03 - 1, itemdescr = "desc-03-1" });

        Data = new List<Items>();
        Data.Add(new Items { itemNumber= 01, itemdescr ="desc-01",Child= Childs });
        Data.Add(new Items { itemNumber= 02, itemdescr ="desc-02", Child = Childs });
        Data.Add(new Items { itemNumber= 03, itemdescr ="desc-03", Child = Childs });
        Data.Add(new Items { itemNumber= 04, itemdescr ="desc-04" , Child = Childs });
        Data.Add(new Items { itemNumber= 05, itemdescr ="desc-05" , Child = Childs });
        Data.Add(new Items { itemNumber= 06, itemdescr ="desc-06" , Child = Childs });
        
    }
}

字符串
用途:

<?xml version="1.0" encoding="utf-8" ?> 
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiMVVMToolkitApp.MyPage"
             xmlns:viewmodel="clr-namespace:MauiMVVMToolkitApp.ViewModels"
             xmlns:mct="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             Title="MyPage">

    <ContentPage.BindingContext>
        <viewmodel:MyViewModel></viewmodel:MyViewModel>
    </ContentPage.BindingContext>
    <VerticalStackLayout>
        <CollectionView x:Name="CollectionViewBoM" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="9" ItemsSource="{Binding Data}">
            <CollectionView.ItemTemplate>
                <DataTemplate >
                    <mct:Expander >
                        <mct:Expander.Header>
                            <Grid HeightRequest="45" MaximumHeightRequest="90" ColumnSpacing="1" RowSpacing="2">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="240"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
                                <!--<BoxView Grid.Column="0" />
                                <BoxView Grid.Column="1" />-->
                                <Label  Grid.Column="0" Text="{Binding itemNumber}" />
                                <Label  Grid.Column="1" Text="{Binding Description}" />
                            </Grid>
                        </mct:Expander.Header>
                        <mct:Expander.Content x:Name="CollectionViewChild">
                            <StackLayout BindableLayout.ItemsSource="{Binding Child}">
                                <BindableLayout.ItemTemplate>
                                    <DataTemplate>
                                        <HorizontalStackLayout>
                                            <Label Text="{Binding itemNumber}" />
                                            <Label Text="{Binding itemdescr}"  Margin="10,0,0,0"/>
                                        </HorizontalStackLayout>
                                    </DataTemplate>
                                </BindableLayout.ItemTemplate>
                            </StackLayout>
                        </mct:Expander.Content>
                    </mct:Expander>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </VerticalStackLayout>
</ContentPage>


注意事项:
为了代码简洁,我注解掉了布局中的两个BoxView
此外,我注意到类Items还应该包含另一个属性Description,并且类Items(Child)的属性,其内部子元素也是Items类型。初始化数据时请注意这一点。

qfe3c7zg

qfe3c7zg2#

首先,我做了以下的名字更改:

  • 项目->项目
  • itemNumber -> ItemNumber
  • itemDescr -> ItemDesc
  • 儿童->儿童
  • 通过使Item继承ObservableObject将其转换为视图模型
  • 让孩子成为可观察的收藏品
public partial class Item : ObservableObject
    {
        [ObservableProperty]
        private int _itemNumber;
        [ObservableProperty]
        private string _itemDesc;
        [ObservableProperty]
        private ObservableCollection<Item> _children = new ObservableCollection<Item>();
    }

字符串
然后,在我的MainViewModel.cs中,我不仅声明了ObservableCollection,而且还实现了SelectedItem。

public partial class MainViewModel: ObservableObject
    {
        [ObservableProperty]
        private ObservableCollection<Item> _items = new ObservableCollection<Item>();

        [ObservableProperty]
        private Item? _selectedItem;
        
        public MainViewModel()
        {
            Item item;
            item = new Item() { ItemNumber = 101, ItemDesc = "Parent Item 101" };
            item.Children.Add(new Item() { ItemNumber = 1001, ItemDesc = "Child Item 1001" });
            item.Children.Add(new Item() { ItemNumber = 1002, ItemDesc = "Child Item 1002" });
            Items.Add(item);
            item = new Item() { ItemNumber = 201, ItemDesc = "Parent Item 201" };
            item.Children.Add(new Item() { ItemNumber = 2001, ItemDesc = "Child Item 2001" });
            item.Children.Add(new Item() { ItemNumber = 2002, ItemDesc = "Child Item 2002" });
            item.Children.Add(new Item() { ItemNumber = 2003, ItemDesc = "Child Item 2003" });
            Items.Add(item);
            SelectedItem = Items[0];
        }
    }


然后,对于UI,我声明了两个CollectionViews,一个用于Master,一个用于Detail。在第一个CollectionView中,我在SelectedItem上执行了一个双向数据绑定(注意,您还需要设置SelectionMode=“Single”)。在第二个CollectionView中,相同的SelectedItem被用作绑定上下文,以便我可以访问Children。最后,降低XAML复杂性的另一种方法是将DataTemplates放在参考资料中,稍后再引用它们的键名。
您应该注意到CollectionViews不是嵌套的,而是按顺序声明的,因此,控制它们的位置应该很简单。我已经使用了一个简单的VerticalStackLayout,但是你可以使用Grid来按你想要的方式排列它们。

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="maui_mvvm_sample.MainPage">
    <ContentPage.Resources>
        <DataTemplate x:Key="parentTemplate">
            <HorizontalStackLayout>
                <Label Text="{Binding ItemNumber}"/>
                <Label Text="{Binding ItemDesc}"/>
            </HorizontalStackLayout>
        </DataTemplate>
        <DataTemplate x:Key="childTemplate">
            <HorizontalStackLayout>
                <Label Text="{Binding ItemNumber}"/>
                <Label Text="{Binding ItemDesc}"/>
            </HorizontalStackLayout>
        </DataTemplate>
    </ContentPage.Resources>
    <VerticalStackLayout>
        <Label Text="Master"/>
        <CollectionView ItemsSource="{Binding Items}"
                        ItemTemplate="{StaticResource parentTemplate}"
                        SelectedItem="{Binding SelectedItem,Mode=TwoWay}"
                        SelectionMode="Single"/>
        <Label Text="Detail"/>
        <CollectionView BindingContext="{Binding SelectedItem}"
                        ItemsSource="{Binding Children}"
                        ItemTemplate="{StaticResource childTemplate}">
        </CollectionView>
    </VerticalStackLayout>
</ContentPage>


如果您不希望在SelectedItem上执行双向绑定,则可以创建First、Previous、Next、Last等导航命令,并以这种方式更新SelectedItem。

相关问题