1
votes

I am trying to use an ObservableCollection of controls (ContentViews) in a CollectionView. The collection of ContentViews are currently being created and populated in the ctor of my ContentPage. I then set the ItemSource of the CollectionView to the property on the page that hold the ObservableCollection. My problem is that the ContentViews do not display at all.

Here is the XAML code from the ContentPage:

    <ContentPage.Content>
        <StackLayout>
            <CollectionView ItemsSource="{Binding MyPolicies}">
                <CollectionView.Header>
                    <StackLayout BackgroundColor="LightGray">
                        <Label Margin="10,0,0,0"
                               Text="My Policies"
                               FontSize="Small"
                               FontAttributes="Bold" />
                    </StackLayout>
                </CollectionView.Header>
            </CollectionView>
        </StackLayout>
    </ContentPage.Content>

Here is the code in the ContentPage constructor that creates ContentViews and adds them to the collection bound to the CollectionView :

    public partial class TestCollectionView : ContentPage
    {
        public ObservableCollection<ThreeLineThreeColumnCardView> MyPolicies { get; private set; } = null;

        public TestCollectionView()
        {
            IList<ThreeLineThreeColumnCardView> sourcePolicies = new List<ThreeLineThreeColumnCardView>();
            CreateMyPolicies(sourcePolicies);

            InitializeComponent();
        }

        private void CreateMyPolicies(IList<ThreeLineThreeColumnCardView> sourcePolicies)
        {
            //
            sourcePolicies.Add(new ThreeLineThreeColumnCardView());

            sourcePolicies.Add(new ThreeLineThreeColumnCardView());

            sourcePolicies.Add(new ThreeLineThreeColumnCardView());

            //
            MyPolicies = new ObservableCollection<ThreeLineThreeColumnCardView>(sourcePolicies);
        }
    }

Here is the ContentView I'm using. You will notice that it has values set as defaults:

<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             x:Class="NGIC_XAML.Controls.CardViews.ThreeLineThreeColumnCardView">
    <Frame WidthRequest="342"
           BackgroundColor="#FFFFFF"
           BorderColor="LightGray"
           CornerRadius="5"
           HasShadow="False"
           Padding="8"
           VerticalOptions="Center"
           HorizontalOptions="Center">
        <Grid WidthRequest="311" Margin="15, 13, 16, 13">
            <Grid.RowDefinitions>
                <RowDefinition Height="20" />
                <RowDefinition Height="30" />
                <RowDefinition Height="20" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Label Grid.Row="0" Grid.Column="0" 
                   Text="{Binding CardTitle, FallbackValue='R0C0'}"
                   FontAttributes="None"
                   FontSize="14"
                   TextColor="{Binding CardTitleColor, FallbackValue='#333333'}"
                   VerticalTextAlignment="Center"
                   HorizontalTextAlignment="Start" />
            <Label Grid.Row="0" Grid.Column="1" 
                   Text="{Binding CardAmount, FallbackValue='R0C1'}"
                   FontAttributes="Bold"
                   FontSize="16"
                   TextColor="{Binding CardAmountColor, FallbackValue='#53585B'}"
                   VerticalTextAlignment="Center"
                   HorizontalTextAlignment="End" />
            <Label Grid.Row="0" Grid.Column="2" 
                   Text="{Binding CardAmount, FallbackValue='R0C2'}"
                   FontAttributes="Bold"
                   FontSize="16"
                   TextColor="{Binding CardAmountColor, FallbackValue='#53585B'}"
                   VerticalTextAlignment="Center"
                   HorizontalTextAlignment="End" />

            <Label Grid.Row="1" Grid.Column="0"
                   Text="{Binding CardDate, FallbackValue='R1C0'}"
                   FontSize="12"
                   TextColor="{Binding CardDateColor, FallbackValue='#70777C'}"
                   VerticalTextAlignment="Center"
                   HorizontalTextAlignment="Start" />
            <Label Grid.Row="1" Grid.Column="1"
                   Text="{Binding CardComment, FallbackValue='R1C1'}"
                   FontSize="12"
                   TextColor="{Binding CardCommentColor, FallbackValue='#70777C'}"
                   VerticalTextAlignment="Center"
                   HorizontalTextAlignment="End" />
            <Label Grid.Row="1" Grid.Column="2"
                   Text="{Binding CardComment, FallbackValue='R1C2'}"
                   FontSize="12"
                   TextColor="{Binding CardCommentColor, FallbackValue='#70777C'}"
                   VerticalTextAlignment="Center"
                   HorizontalTextAlignment="End" />

            <Label Grid.Row="2" Grid.Column="0"
                   Text="{Binding CardDate, FallbackValue='R2C0'}"
                   FontSize="12"
                   TextColor="{Binding CardDateColor, FallbackValue='#70777C'}"
                   VerticalTextAlignment="Center"
                   HorizontalTextAlignment="Start" />
            <Label Grid.Row="2" Grid.Column="1"
                   Text="{Binding CardComment, FallbackValue='R2C1'}"
                   FontSize="12"
                   TextColor="{Binding CardCommentColor, FallbackValue='#70777C'}"
                   VerticalTextAlignment="Center"
                   HorizontalTextAlignment="End" />
            <Label Grid.Row="2" Grid.Column="2"
                   Text="{Binding CardComment, FallbackValue='R2C2'}"
                   FontSize="12"
                   TextColor="{Binding CardCommentColor, FallbackValue='#70777C'}"
                   VerticalTextAlignment="Center"
                   HorizontalTextAlignment="End" />
        </Grid>
    </Frame>
</ContentView>

And this is what the ContentView looks like in its raw state:

raw card view

So, my question is how do I get the collection of "cards" to display in the CollectionView on my ContentPage?

UPDATE Added to the ContentPage:

                    <DataTemplate>
                        <Grid Padding="10">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />
                            </Grid.ColumnDefinitions>
                            <cards:ThreeLineCardView />
                        </Grid>
                    </DataTemplate>
                </CollectionView.ItemTemplate>

UPADTE Demonstrate that the pre-populated card (a ContentView) can be displayed in the Grid outside of the CollectionView

    <ContentPage.Content>
        <StackLayout>
            <!--<CollectionView ItemsSource="{Binding MyPolicies}">
                <CollectionView.Header>
                    <StackLayout BackgroundColor="LightGray">
                        <Label Margin="10,0,0,0"
                               Text="My Policies"
                               FontSize="Small"
                               FontAttributes="Bold" />
                    </StackLayout>
                </CollectionView.Header>
                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <Grid Padding="10">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />
                            </Grid.ColumnDefinitions>
                            <cards:ThreeLineCardView />
                        </Grid>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>-->
            <Grid Padding="10">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                </Grid.ColumnDefinitions>
                <cards:ThreeLineCardView />
            </Grid>
        </StackLayout>
    </ContentPage.Content>

enter image description here

1
you haven't supplied any template for your CollectionViewJason
OK< but if I am supplying complete objects to use in the CollectionView, why do I need a template? For example, in the documentaation the CollectionView's ItemSuorce is set to an array of strings that are output without a template.JNickVA1
because in a simple case it will just use ToString() to generate the output, but this is not a simple case. You appear to be making it more complex than necessary - I don't think the data binding in your ContentView will work like you want it. A better approach would be to use your ContentView as the template and your data as the ItemsSourceJason
I added an ItemTemplate (see the UPDATE to my question) and it still doesn't display. There should be a way to do this without having to include the complete layout of the ContentView in the ItemTemplate.JNickVA1
Did you change your ItemsSource? If you're new to this I'd suggest you start with something much simpler, get it to work, then build up from there.Jason

1 Answers

1
votes

I'm not sure whether this is your want . If no , you can comment bellow .

I create a ContentView named CardView , the xaml code is the same as your shared .

Then used in Xaml of ContentPage as follow :

<CollectionView x:Name="collectionView"
                ItemsLayout="VerticalList">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <appentrytest:CardView />
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

The CardViewModel is :

public class CardViewModle
{
    public string CardTitle { set; get; }
    public string CardAmount { set; get; }
    public string CardDate { set; get; }
    public string CardComment { set; get; }
}

In ContentPage ,set data source for CollectView :

public partial class PageFourth : ContentPage
{
    public List<CardViewModle> cardViewModles { set; get; }

    public PageFourth()
    {
        InitializeComponent();

        cardViewModles = new List<CardViewModle>();
        cardViewModles.Add(new CardViewModle() { CardTitle = "1", CardAmount = "2", CardComment = "one more", CardDate = "2020-06-17" });
        cardViewModles.Add(new CardViewModle() { CardTitle = "2", CardAmount = "5", CardComment = "two more", CardDate = "2020-06-17" });
        cardViewModles.Add(new CardViewModle() { CardTitle = "3", CardAmount = "6", CardComment = "three more", CardDate = "2020-06-17" });
        cardViewModles.Add(new CardViewModle() { CardTitle = "4", CardAmount = "8", CardComment = "four more", CardDate = "2020-06-17" });
        cardViewModles.Add(new CardViewModle() { CardTitle = "5", CardAmount = "12", CardComment = "five more", CardDate = "2020-06-17" });
        cardViewModles.Add(new CardViewModle() { CardTitle = "6", CardAmount = "18", CardComment = "six more", CardDate = "2020-06-17" });
        cardViewModles.Add(new CardViewModle() { CardTitle = "7", CardAmount = "80", CardComment = "seven more", CardDate = "2020-06-17" });
        cardViewModles.Add(new CardViewModle() { CardTitle = "8", CardAmount = "20", CardComment = "eight more", CardDate = "2020-06-17" });

        collectionView.ItemsSource = cardViewModles;

    }
}

The effect :

enter image description here

======================Update===========================

If want each item of CollectionView also can contain a list of Controls , you can use Bindable Layouts to achieve that .

The Xaml of CardView as follow :

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             x:Class="AppEntryTest.CardView">
  <ContentView.Content>
        <Frame WidthRequest="342"
               BackgroundColor="#FFFFFF"
               BorderColor="LightGray"
               CornerRadius="5"
               HasShadow="False"
               Padding="8"
               VerticalOptions="Center"
               HorizontalOptions="Center">
            <Grid WidthRequest="311"
                  Margin="15, 13, 16, 13">
                <Grid.RowDefinitions>
                    <RowDefinition Height="20" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="40*" />
                    <ColumnDefinition Width="60*" />
                </Grid.ColumnDefinitions>
                <Label Grid.Row="0"
                       Grid.Column="0"
                       Text="{Binding CardTitle, FallbackValue='R0C0'}"
                       FontAttributes="None"
                       FontSize="14"
                       TextColor="{Binding CardTitleColor, FallbackValue='#333333'}"
                       VerticalTextAlignment="Center"
                       HorizontalTextAlignment="Start" />
                <Label Grid.Row="0"
                       Grid.Column="1"
                       Text="{Binding CardAmount, FallbackValue='R0C1'}"
                       FontAttributes="Bold"
                       FontSize="16"
                       TextColor="{Binding CardAmountColor, FallbackValue='#53585B'}"
                       VerticalTextAlignment="Center"
                       HorizontalTextAlignment="Center" />

                <StackLayout Grid.Row="1"
                            Grid.ColumnSpan="2"
                            Orientation="Vertical"
                            BindableLayout.ItemsSource="{Binding CommetList}">
                    <BindableLayout.ItemTemplate>
                        <DataTemplate>
                            <StackLayout Orientation="Horizontal">
                                <Label Grid.Column="0"
                                       Text="{Binding CardDate, FallbackValue='R1C0'}"
                                       FontSize="12"
                                       TextColor="{Binding CardDateColor, FallbackValue='#70777C'}"
                                       WidthRequest="300"
                                       VerticalTextAlignment="Center"
                                       HorizontalTextAlignment="Start" />
                                <Label Text="{Binding CardComment, FallbackValue='R1C1'}"
                                       FontSize="12"
                                       TextColor="{Binding CardCommentColor, FallbackValue='#70777C'}"
                                       WidthRequest="900"
                                       VerticalTextAlignment="Center"
                                       HorizontalTextAlignment="Center" />
                            </StackLayout>
                        </DataTemplate>
                    </BindableLayout.ItemTemplate>
                </StackLayout>
            </Grid>
        </Frame>
    </ContentView.Content>
</ContentView>

Also used in ContentPage :

<ContentPage.Content>
    <StackLayout>
        <Label Text="Welcome to Xamarin.Forms!"
            VerticalOptions="CenterAndExpand" 
            HorizontalOptions="CenterAndExpand" />
        <CollectionView x:Name="collectionView"
                        ItemsLayout="VerticalList">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <appentrytest:CardView />
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </StackLayout>
</ContentPage.Content>

Here need to create a CardCommentModel :

public class CardCommentModel
{
    public string CardDate { set; get; }
    public string CardComment { set; get; }
}

And modify CardViewModle as follow :

public class CardViewModle
{
    public string CardTitle { set; get; }
    public string CardAmount { set; get; }

    public List<CardCommentModel> CommetList { set; get; }
}

Then in ContenPage , setting data for CollectView :

public partial class PageFourth : ContentPage
{
    public List<CardViewModle> cardViewModles { set; get; }

    public PageFourth()
    {
        InitializeComponent();

        List<CardCommentModel> cardCommentModelsOne = new List<CardCommentModel>();
        cardCommentModelsOne.Add(new CardCommentModel() { CardDate = "13:12:16", CardComment = "comment one" });
        cardCommentModelsOne.Add(new CardCommentModel() { CardDate = "13:15:16", CardComment = "comment two" });

        List<CardCommentModel> cardCommentModelsTwo = new List<CardCommentModel>();
        cardCommentModelsTwo.Add(new CardCommentModel() { CardDate = "14:12:16", CardComment = "comment one" });
        cardCommentModelsTwo.Add(new CardCommentModel() { CardDate = "15:22:16", CardComment = "comment two" });
        cardCommentModelsTwo.Add(new CardCommentModel() { CardDate = "15:42:16", CardComment = "comment three" });

        List<CardCommentModel> cardCommentModelsThree = new List<CardCommentModel>();
        cardCommentModelsThree.Add(new CardCommentModel() { CardDate = "15:32:16", CardComment = "comment one" });
        cardCommentModelsThree.Add(new CardCommentModel() { CardDate = "15:29:11", CardComment = "comment two" });
        cardCommentModelsThree.Add(new CardCommentModel() { CardDate = "16:12:16", CardComment = "comment three" });
        cardCommentModelsThree.Add(new CardCommentModel() { CardDate = "17:28:19", CardComment = "comment four" });
        cardCommentModelsThree.Add(new CardCommentModel() { CardDate = "18:42:26", CardComment = "comment five" });

        cardViewModles = new List<CardViewModle>();
        cardViewModles.Add(new CardViewModle() { CardTitle = "First Title", CardAmount = "Count : "+cardCommentModelsOne.Count.ToString(), CommetList= cardCommentModelsOne});
        cardViewModles.Add(new CardViewModle() { CardTitle = "Second Title", CardAmount = "Count : " + cardCommentModelsTwo.Count.ToString(), CommetList= cardCommentModelsTwo });
        cardViewModles.Add(new CardViewModle() { CardTitle = "Third Title", CardAmount = "Count : " + cardCommentModelsThree.Count.ToString(), CommetList= cardCommentModelsThree });

        collectionView.ItemsSource = cardViewModles;

    }
}

The effect :

enter image description here