简体   繁体   中英

Only the first item in a list is rendered when I try to output a collectionview inside a collectionview in Xamarin Forms

I'm trying to render a complex object in a list in a Xamarin view. the object I'm trying to list out is a collection of viewmodels. One of the properties of each of these viewmodels is another collection.

To illustrate, the list contains the following members:

public class ItemsViewModel : BaseViewModel
    {
        public int Id { get; private set; }
        public bool UsedOption1 { get; private set; }
        public bool UsedOption2 { get; private set; }
        public bool UsedOption3 { get; private set; }
        public bool UsedOption4 { get; private set; }
        public List<ActivityViewModel> Activities { get; private set; }
    }

The List looks like this:

public class ActivityViewModel
{
    public string LocationDisplayName { get; private set; }
    public int SwimmersEaten { get; private set; }
}

The ActivityViewModel could have 4 items at most. If I use the following code to render the Viewmodel:

<RefreshView IsRefreshing="{Binding IsBusy, Mode=TwoWay}" Command="{Binding LoadItemsCommand}">
        <CollectionView x:Name="ItemsCollectionView"
                ItemsSource="{Binding ItemsViewModel}">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <StackLayout Padding="10">
                        <Label Text="{Binding Title}"/>
                        <CollectionView x:Name="Actions"
                            ItemsSource="{Binding Activities}">
                            <CollectionView.ItemTemplate>
                                <DataTemplate>
                                    <StackLayout Padding="10" Orientation="Horizontal">
                                        <Label Text="{Binding DisplayName}"/>
                                        <Label Text="{Binding NumberOfGroups}"/>
                                    </StackLayout>
                                </DataTemplate>
                            </CollectionView.ItemTemplate>
                        </CollectionView>
                        <Label Text="Used Option 1"
                                IsVisible="{Binding UsedOption1}"/>
                        <Label Text="Used Option 2"
                                IsVisible="{Binding UsedOption2}"/>
                        <Label Text="Used Option 3"
                                IsVisible="{Binding UsedOption3}"/>
                        <Label Text="Used Option 4"
                                IsVisible="{Binding UsedOption4}"/>
                    </StackLayout>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </RefreshView> 

I get the first item in the list rendered almost as I want, albeit missing the used options on the end. My rendering looks something like:

Title 1
  a 0
  b 2
  c 0
  d 1

I get the title of the first top level item, the display name and number of groups for each of the 4 items within. The trouble is there are subsequent items in my list that aren't appearing. I can only get items beyond the first in my list to show if I chop out the lister in the middle, like this:

<RefreshView IsRefreshing="{Binding IsBusy, Mode=TwoWay}" Command="{Binding LoadItemsCommand}">
        <CollectionView x:Name="ItemsCollectionView"
                ItemsSource="{Binding ItemsViewModel}">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <StackLayout Padding="10">
                        <Label Text="{Binding Title}"/>
                        <Label Text="Used Option 1"
                                IsVisible="{Binding UsedOption1}"/>
                        <Label Text="Used Option 2"
                                IsVisible="{Binding UsedOption2}"/>
                        <Label Text="Used Option 3"
                                IsVisible="{Binding UsedOption3}"/>
                        <Label Text="Used Option 4"
                                IsVisible="{Binding UsedOption4}"/>
                    </StackLayout>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </RefreshView> 

This renders the title and options for all the viewmodels in my list, like this:

Title 1
Used Option 3

Title 2
Used Option 2
Used Option 3

I can see the presence of the inner collectionview is doing something odd to prevent the rendering of items beyond its listing, preventing the resumption of rendering the contents of the outer list. I'm definitely missing something but can't figure it out. How can I work around this apparent limitation?

I couldn't find an answer that let me render nested lists, which Jason said to be impossible in a comment.

Since I know my ViewModel will only need to render a list of no more than 4 items, my soluton was to add the following members to ItemsViewModel:

public ActivityViewModel Action1 => Activities?.FirstOrDefault();
public ActivityViewModel Action2 => Activities?.Skip(1).FirstOrDefault();
public ActivityViewModel Action3 => Activities?.Skip(2).FirstOrDefault();
public ActivityViewModel Action4 => Activities?.Skip(3).FirstOrDefault();

And my view now looks like this:

<RefreshView IsRefreshing="{Binding IsBusy, Mode=TwoWay}" Command="{Binding LoadItemsCommand}">
    <CollectionView x:Name="ItemsCollectionView"
            ItemsSource="{Binding ItemsViewModel}">
        <CollectionView.ItemTemplate>
            <DataTemplate>
                <StackLayout Orientation="Horizontal">
                    <Label Text="{Binding Title}"/>
                    <Label Text="{Binding Action1.DisplayName}"/>
                    <Label Text="{Binding Action1.NumberOfGroups}"/>
                    <Label Text="{Binding Action2.DisplayName}"/>
                    <Label Text="{Binding Action2.NumberOfGroups}"/>
                    <Label Text="{Binding Action3.DisplayName}"/>
                    <Label Text="{Binding Action3.NumberOfGroups}"/>
                    <Label Text="{Binding Action4.DisplayName}"/>
                    <Label Text="{Binding Action4.NumberOfGroups}"/>
                    <Label Text="Used Option 1"
                        IsVisible="{Binding UsdOption1}"/>
                    <Label Text="Used Option 2"
                        IsVisible="{Binding UsdOption2}"/>
                    <Label Text="Used Option 3"
                        IsVisible="{Binding UsdOption3}"/>
                    <Label Text="Used Option 4"
                        IsVisible="{Binding UsdOption4}"/>
                </StackLayout>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</RefreshView> 

Not an ideal solution because of duplicate entries in the view's data template, but an effective workaround.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM