shahar eldad
shahar eldad

Reputation: 862

Xamarin Forms - A card holding a ListView inside has a height very large

I have a ListView with items and one of the items is a DataTemplate with a ListView inside of it.

The issue here is that this DataTemplate is renderred very high without any need.

Here is a link to a screenshot of the outcome:

This is how it looks like.

https://i.sstatic.net/gBxpb.jpg

Here is the code:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:vm="clr-namespace:MyNotes.ViewModels"
    xmlns:converters="clr-namespace:MyNotes.Converters"
    xmlns:behaviors="clr-namespace:MyNotes.Behavior"
    xmlns:selectors="clr-namespace:MyNotes.Selectors"
    x:Class="MyNotes.Views.MainView">

    <ContentPage.Resources>
        <converters:CollectionEmptyConverter x:Key="CollectionEmptyConverter"/>
        <DataTemplate x:Key="StringTemplate">
            <ViewCell>
                <Label Text="{Binding}"/>
            </ViewCell>
        </DataTemplate>
        <DataTemplate x:Key="DefaultItemTemplate">
            <ViewCell>
                <Frame OutlineColor="Black" Margin="10">
                    <Grid Margin="10">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="auto"/>
                            <RowDefinition Height="auto"/>
                        </Grid.RowDefinitions>
                        <Label Text="{Binding Title}" FontAttributes="Bold"/>
                        <Label Text="Unknow Item" Margin="0,10,0,0" Grid.Row="1"/>
                    </Grid>
                </Frame>
            </ViewCell>
        </DataTemplate>
        <DataTemplate x:Key="TodoItemTemplate">
            <ViewCell>
                <Frame OutlineColor="Black" Margin="10">
                    <Grid Margin="10">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="auto"/>
                            <RowDefinition Height="auto"/>
                        </Grid.RowDefinitions>
                        <Label Text="{Binding Title}" FontAttributes="Bold"/>
                        <Label Text="{Binding Content}" Margin="0,10,0,0" Grid.Row="1"/>
                    </Grid>
                </Frame>
            </ViewCell>
        </DataTemplate>
        <DataTemplate x:Key="ListItemTemplate">
            <ViewCell>
                <Frame OutlineColor="Black">
                    <Grid Margin="10">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="auto"/>
                            <RowDefinition Height="auto"/>
                        </Grid.RowDefinitions>
                        <Label Text="{Binding Title}"
                                FontAttributes="Bold"/>
                        <ListView ItemsSource="{Binding Items}"
                                    Margin="0,10,0,0"
                                    Grid.Row="1"
                                    ItemTemplate="{StaticResource StringTemplate}"/>
                    </Grid>
                </Frame>
            </ViewCell>
        </DataTemplate>
        <selectors:ItemTypeSelector x:Key="ItemTypeSelector"
                                    TodoItemTemplate="{StaticResource TodoItemTemplate}"
                                    ListItemTemplate="{StaticResource ListItemTemplate}"/>
    </ContentPage.Resources>
    <ContentPage.BindingContext>
        <vm:MainViewModel/>
    </ContentPage.BindingContext>
    <ContentPage.Content>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"/>
            </Grid.RowDefinitions>
            <Label Text="No notes yet. Add some."
                    IsVisible="{Binding Collection, Converter={StaticResource CollectionEmptyConverter}}"
                    VerticalOptions="CenterAndExpand"
                    HorizontalOptions="CenterAndExpand" />
            <ListView ItemsSource="{Binding Collection}"
                        IsVisible="{Binding Collection, Converter={StaticResource CollectionEmptyConverter}, ConverterParameter=true}"
                        ItemTemplate="{StaticResource ItemTypeSelector}"/>
        </Grid>
    </ContentPage.Content>
</ContentPage>

I tried a lot of solutions without luck, e.g.:

1. I can't set the height of the listview
2. HasUnevenRows didn't work for me
3. I have rows of different height so setting RowHeight is not an option
4. Tried to investigate using behaviors and found nothing to assist me.

I have read in several places that the issue is most likely to be related to the fact that I have a ListView inside a ListView (in the DataTemplate). Since it is a collection of items where some items can have a list of items inside I don't see how else I can solve this.

Any help direction will be great.

Thanks

Edit: I've checked a theory with a much smaller example

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <ListView ItemsSource="{Binding Collection}"
              BackgroundColor="Yellow"/>
    <Label Text="bla bla bla"
           Grid.Row="1"/>
</Grid>

In this example I assumed the listview would take only the place needed but it doesn't, it takes the whole app height and I can't event see the text "bla bla bla". Why is this behavior???

Upvotes: 0

Views: 246

Answers (2)

nevermore
nevermore

Reputation: 15796

For your second question:

In your code snippet, the height of the first row is set to Auto which means that

the object should be sized to the available size in layout so that the first row will size to fit its content.

And the ListView is in this row, in that case, the ListView will auto fill with the whole screen to fit its content.

The second row is set to *,which means that

after the auto rows are calculated, the row gets part of the remaining height.

So after the auto rows are calculated , the remaining height for your label is 0.This is why you can't even see the text "bla bla bla".

I verify this conclusion by view the ListView and Label's height in code behind.

 public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();


            this.SizeChanged += MainPage_SizeChanged; 

        }

        private void MainPage_SizeChanged(object sender, EventArgs e)
        {
            //ListView height
            Double a = myListView.Height;

            //Label height
            Double b = myLabel.Height;

        }
    }

Here is the result:Height of <code>ListView</code> and <code>Label</code>

Upvotes: 1

shahar eldad
shahar eldad

Reputation: 862

I found a solution to my first question "ANy help direction will be great". I found a github project in this link that does the job pretty good. It gives me an ItemsControl which I can assign a source and an item template. I wrapped it in a ScrollView and got a ListView which works as expected.

Here is a sample usage:

<ScrollView>
    <!-- Place new controls here -->
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <controls:ItemsControl ItemsSource="{Binding Collection}"
                           BackgroundColor="Beige">
            <controls:ItemsControl.ItemTemplate>
                <DataTemplate>
                    <ContentView>
                        <Frame OutlineColor="Black" HasShadow="True" IsClippedToBounds="True" Margin="10">
                            <StackLayout>
                                <Label Text="{Binding Title}"
                                   FontAttributes="Bold"/>
                                <ScrollView>
                                    <controls:ItemsControl ItemsSource="{Binding InnerCollection}"
                                                   Margin="10,0,0,0"/>
                                </ScrollView>
                            </StackLayout>
                        </Frame>
                    </ContentView>
                </DataTemplate>
            </controls:ItemsControl.ItemTemplate>
        </controls:ItemsControl>
        <!--<ListView ItemsSource="{Binding Collection}"
              BackgroundColor="Yellow"/>-->
        <Label Text="bla bla bla"
           Grid.Row="1"/>
    </Grid>
</ScrollView>

As for my second question "Why is this behavior???" - I still don't know the answer but at least I can make progress

Upvotes: 0

Related Questions