How to hide the empty rows of a list view in xamarin.forms
Asked Answered
A

3

9

I have a StackLayout with a ListView and I have an add-button that I want to display right under the ListView. But the ListView displays many rows which are not used. Just empty rows, this is forcing my button to display at the bottom of the page. I've been messing with the VerticalOptions all day but cannot get the rows to disappear.

This is my XAML 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:local="clr-namespace:LiquitMobileApp"
             x:Class="LiquitMobileApp.MainPage"
             Title="Settings"
             >

    <StackLayout BackgroundColor="LightGray">
        <Label Text="Liquit Zones" TextColor="Gray" FontSize="Small" Margin="10"/>
        <StackLayout AbsoluteLayout.LayoutBounds="10,10,10,10">
            <ListView x:Name="UsingZone" SeparatorColor="LightGray" ItemTapped="ZonesList_ItemTapped" RowHeight="60" BackgroundColor="Green"  >
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <ViewCell.ContextActions>
                                <MenuItem Clicked="OnEdit" Text="Edit" />
                                <MenuItem Clicked="OnDelete" CommandParameter="{Binding .}" Text="Trash" IsDestructive="True" />
                            </ViewCell.ContextActions>
                            <StackLayout Padding="15, 5, 0, 0" Orientation="Horizontal" BackgroundColor="White">
                                <Image Source="{Binding Image}" HorizontalOptions="Start" AbsoluteLayout.LayoutBounds="250.25, 0.25, 50, 50 "/>
                                <StackLayout Orientation="Vertical">
                                <Label Text = "{Binding Name}" FontSize="20" TextColor="Black" AbsoluteLayout.LayoutBounds="0.25, 0.25, 400, 40"/>
                                <Label Text = "{Binding Address}" TextColor="LightGray" AbsoluteLayout.LayoutBounds="50, 35, 200, 25"/>
                                </StackLayout>
                            </StackLayout>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
                <ListView.Footer>
                    <Label />
                </ListView.Footer>
            </ListView>
            <Button Text="Add Zone" TextColor="Black" HorizontalOptions="FillAndExpand" FontSize="Medium" Clicked="Button_Clicked" BackgroundColor="White"/>
        </StackLayout>
    </StackLayout>
</ContentPage>

Picture of the list and button:

Picture of the list and the add-button

Aether answered 12/6, 2017 at 13:54 Comment(10)
I guess the problem is the ListView's height. If you not explicit specify, it assumes a default value that is too bigwhen we have few itens... I'm making a work around setting dinamically the HeightRequest property of my listview while don't find a better solutionDenominate
Are empty rows loaded from a bound data source or are they created by default?Ablepsia
@KrzysztofBracha they are created by default.Aether
If you control list height to have only filled rows what do you expect from Add button, jump up and down under the list depending on list height?Cricoid
@YuriS I've edited my post, u can see the list, and the add button now, i want the green rows to disappear and the add button to show right under the last ListItemAether
Looks like you need a custom renderer. Unfortunately my MAC died after installing Sierra and I couldn't try it. Here is the link, please let me know if that worked. forums.xamarin.com/discussion/39200/…. BTW, you are using AbsoluteLayout.LayoutBounds in StackLayout. Does it work for you?Cricoid
Using the strategy that was signed as answer. Wont work on my code.. And i've set the AbsoluteLayout.Bounds : <StackLayout AbsoluteLayout.LayoutBounds="10,10,10,10">. But this wont help. Any other suggestions @YuriSAether
Why you are setting Absolute bounds on stack layout? That is not going to work at all. How many items you want to display (being visible)? Or you want the list resize every time an item added?Cricoid
Do you expect Add button to move up and down as you add or remove elements from list?Cricoid
I want the list to resize everytime an item is added, and i expect the add button to move up and down as i add or remove items yes. @YuriSAether
C
7

So, the solution I found is to force listview layout every time you add/remove an item. You also need to wrap the list in stacklayout.

<StackLayout BackgroundColor="LightGray">
    <Label Text="Liquit Zones" TextColor="Gray" FontSize="Small" Margin="10"/>

    <StackLayout>
    <ListView x:Name="ItemsListView" SeparatorColor="LightGray" BackgroundColor="Green" RowHeight="60" >
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <ViewCell.ContextActions>
                        <MenuItem Clicked="AddItemClicked" Text="Add" />
                        <MenuItem Clicked="RemoveItemClicked" CommandParameter="{Binding .}" Text="Trash" IsDestructive="True" />
                    </ViewCell.ContextActions>
                    <StackLayout Padding="15, 5, 0, 0" Orientation="Horizontal" BackgroundColor="White">
                        <Image Source="{Binding Image}" HorizontalOptions="Start"/>
                        <StackLayout Orientation="Vertical">
                            <Label Text = "{Binding ItemText}" FontSize="20" TextColor="Black" />
                            <Label Text = "{Binding ItemDetail}" TextColor="LightGray" />
                        </StackLayout>
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
        <ListView.Footer>
            <Label />
        </ListView.Footer>
    </ListView>
    </StackLayout>

    <Button Text="Add Item" TextColor="Black" HorizontalOptions="FillAndExpand" FontSize="Medium" Clicked="AddItemClicked" BackgroundColor="White"/>
</StackLayout>

Because you know your cell height you can do this:

       void AddItemClicked(object sender, EventArgs e)
        {
            SampleData data = new SampleData();
            data.ItemText = "An Item";
            data.ItemDetail = "Item - " + (itemsListCollection.Count + 1).ToString();
            itemsListCollection.Add(data);

            ItemsListView.HeightRequest = itemsListCollection.Count * 60;
            //ForceLayout();
        }

    void RemoveItemClicked(object sender, EventArgs e)
    {

        SampleData item =(SampleData)((MenuItem)sender).CommandParameter;
        if (item != null)
        {
            itemsListCollection.Remove(item);
        }
        ItemsListView.HeightRequest = itemsListCollection.Count * 60;

    }


class SampleData:INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private string itemText;
    public string ItemText
    {
        get
        {
            return itemText;
        }
        set
        {
            itemText = value;
            NotifyPropertyChanged("ItemText");
        }
    }
    private string itemDetail;
    public string ItemDetail
    {
        get
        {
            return itemDetail;
        }
        set
        {
            itemDetail = value;
            NotifyPropertyChanged("ItemDetail");
        }
    }
    private void NotifyPropertyChanged(string propName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propName));
        }
    }
}

enter image description here

Cricoid answered 19/6, 2017 at 18:59 Comment(3)
Thanks! This did it for me : ItemsListView.HeightRequest = itemsListCollection.Count * 60;Aether
How can I make that 60 dynamically determined?Hotchpot
Not sure what you meanCricoid
D
9

An easy way to remove the empty rows of a ListView is to set an empty footer for the ListView.

ListView HeaderList = new ListView()
    {
       Footer = ""
    };

or in XAML

<ListView  x:Name="HeaderList" Footer=""></ListView>
Degauss answered 23/8, 2019 at 9:19 Comment(0)
C
7

So, the solution I found is to force listview layout every time you add/remove an item. You also need to wrap the list in stacklayout.

<StackLayout BackgroundColor="LightGray">
    <Label Text="Liquit Zones" TextColor="Gray" FontSize="Small" Margin="10"/>

    <StackLayout>
    <ListView x:Name="ItemsListView" SeparatorColor="LightGray" BackgroundColor="Green" RowHeight="60" >
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <ViewCell.ContextActions>
                        <MenuItem Clicked="AddItemClicked" Text="Add" />
                        <MenuItem Clicked="RemoveItemClicked" CommandParameter="{Binding .}" Text="Trash" IsDestructive="True" />
                    </ViewCell.ContextActions>
                    <StackLayout Padding="15, 5, 0, 0" Orientation="Horizontal" BackgroundColor="White">
                        <Image Source="{Binding Image}" HorizontalOptions="Start"/>
                        <StackLayout Orientation="Vertical">
                            <Label Text = "{Binding ItemText}" FontSize="20" TextColor="Black" />
                            <Label Text = "{Binding ItemDetail}" TextColor="LightGray" />
                        </StackLayout>
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
        <ListView.Footer>
            <Label />
        </ListView.Footer>
    </ListView>
    </StackLayout>

    <Button Text="Add Item" TextColor="Black" HorizontalOptions="FillAndExpand" FontSize="Medium" Clicked="AddItemClicked" BackgroundColor="White"/>
</StackLayout>

Because you know your cell height you can do this:

       void AddItemClicked(object sender, EventArgs e)
        {
            SampleData data = new SampleData();
            data.ItemText = "An Item";
            data.ItemDetail = "Item - " + (itemsListCollection.Count + 1).ToString();
            itemsListCollection.Add(data);

            ItemsListView.HeightRequest = itemsListCollection.Count * 60;
            //ForceLayout();
        }

    void RemoveItemClicked(object sender, EventArgs e)
    {

        SampleData item =(SampleData)((MenuItem)sender).CommandParameter;
        if (item != null)
        {
            itemsListCollection.Remove(item);
        }
        ItemsListView.HeightRequest = itemsListCollection.Count * 60;

    }


class SampleData:INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private string itemText;
    public string ItemText
    {
        get
        {
            return itemText;
        }
        set
        {
            itemText = value;
            NotifyPropertyChanged("ItemText");
        }
    }
    private string itemDetail;
    public string ItemDetail
    {
        get
        {
            return itemDetail;
        }
        set
        {
            itemDetail = value;
            NotifyPropertyChanged("ItemDetail");
        }
    }
    private void NotifyPropertyChanged(string propName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propName));
        }
    }
}

enter image description here

Cricoid answered 19/6, 2017 at 18:59 Comment(3)
Thanks! This did it for me : ItemsListView.HeightRequest = itemsListCollection.Count * 60;Aether
How can I make that 60 dynamically determined?Hotchpot
Not sure what you meanCricoid
S
-3

Hi everyone,

 public class Test
 {
    string Name{get;set;}
 }

Declare globally

  ObservableCollection<Test> objWithEmpty;

In Constructor:

 objWithEmpty=new ObservableCollection<Test>();
 objWithEmpty.Add(new Test(){"Venky"});
 objWithEmpty.Add(new Test(){""});
 objWithEmpty.Add(new Test(){"Raju"});

Now take one more ObservableCollection and check the condition as per your requirement without empty then add that item to objWithOutEmpty Collection then finally add objWithOutEmpty ItemsSource to the ListView.

  ObservableCollection<Test> objWithOutEmpty;

 foreach(var item in objWithEmpty)
   {
        if(item.Name !=null)
           {
                  objWithOutEmpty.Add(new Test(){item.Name});
           }
   };

Now set ItemsSource to the ListView

 listView.ItemsSource=objWithOutEmpty;
Simonetta answered 12/6, 2017 at 16:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.