Home > Net >  How to dynamically add items to a ListView based on a List on XAML?
How to dynamically add items to a ListView based on a List on XAML?

Time:12-28

I am trying to create a <ListView> with XAML. The list is supposed to show the contents of a list of the class Task.

taskView.ItemsSource = company.tasks;

The version of XAML I am using is the one contemplated on MAUI therefore most tutorials show elements than are not included in the XAML version used.

I tried to do it as following:

        <ListView x:Name="taskView"
      Margin="120,0,0,60"
      ItemsSource="{Binding tasks}"
      ItemSelected="taskView_SelectionChanged">
        <ListView.ItemTemplate>
            <DataTemplate>
                <TextCell Text="{Binding name}"/>
                <TextCell Text="{Binding status}"/>
                <TextCell Text="{Binding dedaline}"/>
                <TextCell Text="{Binding description}"/>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

But it did not work. It would neither open the app nor throw an exception.

If I leave only one <TextCell>, it opens and shows (only the name). How can I show more details?

Here is the class Task:

    public class Task
    {
        public Task(string name, List<string> departments, Status status, DateOnly deadline, string description)
        {
            this.name = name;
            this.departments = departments;
            this.status = status;
            this.deadline = deadline;
            this.description = description;
        }

        public string name { get; private set; }
        public List<string> departments { get; private set; } = new List<string>();
        public Status status { get; private set; }
        public DateOnly deadline { get; private set; }
        public Employee? author { get; set; }
        public string description { get; private set; }
        public List<Employee> employees { get; private set; } = new List<Employee>();
    }

I am fairly new to XAML and would candidly appreciate some help. Thank you.

CodePudding user response:

First an irrelevant thing. The class "Task" may cause you problem because you already have System.Threading.Task in .net.

You shouldn't bind the ListView (or CollectionView) to a source twice for the same purpose as @Jason said.

XAML FILE

<ContentPage
    x:Class="MauiApp.MainPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:models="clr-namespace:MauiApp.Models"
    xmlns:views="clr-namespace:MauiApp.Views"
    x:DataType="views:MainPage">

    <CollectionView            
        ItemsSource="{Binding Tasks}">

        <CollectionView.ItemTemplate>
            <DataTemplate x:DataType="models:Task">
                <VerticalStackLayout Margin="15">
                    <Entry Text="{Binding name}" />
                    <Entry Text="{Binding status}" />
                    <Entry Text="{Binding deadline}" />
                    <Entry Text="{Binding description}" />
                </VerticalStackLayout>
            </DataTemplate>
        </CollectionView.ItemTemplate>

    </CollectionView>

</ContentPage>

Check the XML namespaces (xmlns). I assumed you have your Task model inside "Models" folder and your views inside "Views" folder. You need this import because your content page's datatype is binded with MainPage, but your CollectionView is binded with Task class.

Inside DataTemplate you can have only 1 item. So you should choose a container item, like VerticalStackLayout in this answer.

CLASS FILE

public partial class MainPage : ContentPage
{
    public ObservableCollection<Task> Tasks { get; set; } = new ObservableCollection<Task>();

    public MainPage()
    {
        InitializeComponent();
        BindingContext = this;

        Tasks.Add(new Task("task 1", new List<string>() { "dep1", "dep2" }, "status 1", DateOnly.MinValue, "description 1"));
        Tasks.Add(new Task("task 2", new List<string>() { "dep3", "dep4" }, "status 2", DateOnly.MinValue, "description 2"));
    }
}

In your class you could use ObservableCollection and you must bind Context with BindingContext = this;

If you are using MVVM, than you can bind that to your ViewModel.

This should work as expected, although you may need to class OnPropertyChanged if needed.

CodePudding user response:

a ListView's DataTemplate can only contains a single child element. If you want to have multiple data elements, use a ViewCell instead of a TextCell and build your own custom layout

<ViewCell>
   <StackLayout BackgroundColor="#eee"
                    Orientation="Vertical">
     <StackLayout Orientation="Horizontal">
        <Image Source="{Binding image}" />
        <Label Text="{Binding title}"
                            TextColor="#f35e20" />
        <Label Text="{Binding subtitle}" HorizontalOptions="EndAndExpand"
                            TextColor="#503026" />
      </StackLayout>
    </StackLayout>
   </ViewCell>
  • Related