Search code examples
listviewxamarin.formsshow-hide

Xamarin forms: How to hide the repeated month name from the listview?


I have a list of events in my app(UI-1, left side screen), on there month name is repeating always.

I need to remove the repeated month name from the list and need a UI like UI-2(right side).

I am using listview for this feature and following is my code:

In my case, I need to show my list in the month order. I have added my current codes below:

My Model Class:

public class CalendarEvents
    {
        public List<EventsHB> eventsHB { get; set; }
    }

    public class EventsHB
    {
        public string month { get; set; }
        public EventTO eventTO { get; set; }
    }
    public class EventTO
    { 
        public string calendarEventId { get; set; }
        public string title { get; set; }
        public long startDate { get; set; }
        public string startTime { get; set; }
    }

My JSON Response:

"eventsHB": [
        {
            "eventTO": {
                "calendarEventId": 136,
                "title": " school event",
                "startDate": 1561006800000,
                "startTime": "6:15 PM"
            },
            "month": "July"
        },
        {
            "eventTO": {
                "calendarEventId": 139,
                "title": "New Admission Day"
                "startDate": 1560834000000
                "startTime": "10:00 AM"
            },
            "month": "July"
        },
        {
            "eventTO": {
                "calenderId": 810354,
                "title": "event pta"
                "startDate": 1559710800000,
                "startTime": "10:00 AM"
            },
            "month": "June"
        },
       {
            "eventTO": {
                "calendarEventId": 89,
                "title": "Memorial Day Meet",
                "startDate": 1559365200000,
                "startTime": "8:00 AM"
            },
            "month": "June"
        }
    ]

Xaml:

 <ListView x:Name="MyEventsListview"
                      HasUnevenRows="True"
                      ItemsSource="{Binding AllItems,Mode=TwoWay}">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <ViewCell.View>

                                <StackLayout
                                    Orientation="Vertical">

                                        <Label 
                                        Text="{Binding month}"/>

                                        <StackLayout
                                Orientation="Horizontal">

                                            <Grid>
                                                <Grid.ColumnDefinitions>
                                                    <ColumnDefinition Width="50*" />
                                                    <ColumnDefinition Width="50*" />
                                                </Grid.ColumnDefinitions>

                                                <StackLayout
                                            Grid.Column="0"
                                            Orientation="Vertical">

                                                    <Label 
                                            Text="{Binding eventTO.startDate,  Converter={StaticResource dayConverter}}"/>

                                                    <Label 
                                            Text="{Binding eventTO.startDate,  Converter={StaticResource dateConverter}}"/>

                                                    <Label 
                                            Text="{Binding eventTO.startTime}"/>
                                                </StackLayout>

                                                <Label 
                                        Text="{Binding eventTO.title}"/>
                                            </Grid>
                                        </StackLayout>
                                </StackLayout>
                            </ViewCell.View>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
              </ListView>

Viewmodel:

            HttpClient client = new HttpClient();
                var Response = await client.GetAsync("My REST Call");
                if (Response.IsSuccessStatusCode)
                {
                    string response = await Response.Content.ReadAsStringAsync();
                    myevents = new CalendarEvents();
                    if (response != "")
                    {
                        myevents = JsonConvert.DeserializeObject<CalendarEvents>(response.ToString());
                    }
                    AllItems = new ObservableCollection<EventsHB>(myevents.eventsHB);

I don't know what changes need to do in the model class, xaml and ViewModel for grouping the list in month view. Can anyone suggest solution hints?


Solution

  • I write a sample for you to show what model and data you should have to show a Grouped ListView in your case:

    The model and data should be something like this:

    public partial class MainPage : ContentPage
    {
        public ObservableCollection<EventsHB> AllItems { get; set; }
    
    
        public MainPage()
        {
            InitializeComponent();            
    
            AllItems = new ObservableCollection<EventsHB>();
    
            var julyGroup = new EventsHB() {month = "july"};
    
            julyGroup.Add(new EventTO() { calendarEventId = "1", title = "firstTitle", startDate = "01-1-1", startTime = "01-1-1"});
            julyGroup.Add(new EventTO() { calendarEventId = "2", title = "secondTitle", startDate = "02-1-1", startTime = "01-1-2" });
            julyGroup.Add(new EventTO() { calendarEventId = "3", title = "thirdTitle", startDate = "02-1-1", startTime = "01-1-3" });
            julyGroup.Add(new EventTO() { calendarEventId = "4", title = "fourthTitle", startDate = "02-1-1", startTime = "01-1-4" });
    
            var juneGroup = new EventsHB() { month = "june" };
            juneGroup.Add(new EventTO() { calendarEventId = "1", title = "junefirstTitle", startDate = "01-1-1", startTime = "01-1-1" });
            juneGroup.Add(new EventTO() { calendarEventId = "2", title = "junesecondTitle", startDate = "02-1-1", startTime = "01-1-2" });
            juneGroup.Add(new EventTO() { calendarEventId = "3", title = "junethirdTitle", startDate = "02-1-1", startTime = "01-1-3" });
            juneGroup.Add(new EventTO() { calendarEventId = "4", title = "junefourthTitle", startDate = "02-1-1", startTime = "01-1-4" });
    
            AllItems.Add(julyGroup);
            AllItems.Add(juneGroup);
            //...
            //more months like April,May can be added
    
            BindingContext = this;
        }
    
    }
    
    public class EventsHB : ObservableCollection<EventTO>
    {
        public string month { get; set; }
        public EventTO eventTO { get; set; }
    }
    
    public class EventTO
    {
        public string calendarEventId { get; set; }
        public string title { get; set; }
        public string startDate { get; set; }
        public string startTime { get; set; }
    }
    

    And in your json data, the data structure seems not fit the structure I listed in my sample, so what you have to do is to convert your data to the proper structure, I write a test function and you can check if it works:

    //A test function to convert you json array to the array we need
        void test()
        {
    
            EventsHB julyGroup = new EventsHB() { month = "july" }; ;
            EventsHB juneGroup = new EventsHB() { month = "june" };
            //other months group
    
    
            foreach (var item in AllItems)
            {
                EventsHB hb = item;
                if (hb.month == "july")
                {
                    julyGroup.Add(hb.eventTO);
                }
                else if (hb.month == "june")
                {
                    juneGroup.Add(hb.eventTO);
                }//...other months
            }
    
            //at last, add them to All items.
            AllItems.Add(julyGroup);
            AllItems.Add(juneGroup);
            //...add other months
        }
    

    You can convert it in your own ways.

    The sample is here: grouped-listView

    Refer: customizing-list-appearance#grouping

    Update:

    Really complex to convert data structure in app side, I convert it for you and I add comments everyWhere I updated the code in the project.

    The reason you get the exception was because the model EventsHB : ObservableCollection<EventTO>, so I create a new one here to deserialize json.

    public class CalendarEvents
    {
        //update here: here should be List<EventsHBTwo>
        public List<EventsHBTwo> eventsHB { get; set; }
    }
    
    //update use this one to shou grouped list data
    public class EventsHB : ObservableCollection<EventTO>
    {
        public string month { get; set; }
        public EventTO eventTO { get; set; }
    }
    
    //Update: use this one to deserialize json
    public class EventsHBTwo
    {
        public string month { get; set; }
        public EventTO eventTO { get; set; }
    }
    

    In ViewModel.cs:

    //Update: add a new tempItem to get json data
    public ObservableCollection<EventsHBTwo> tempItem
    {
        get
        {
            return _tempItems;
        }
        set
        {
            _tempItems = value;
            OnPropertyChanged("tempItem");
        }
    }
    

    And then use this tempItem to get json data:

       tempItem = new ObservableCollection<EventsHBTwo>(myevents.eventsHB);    
       //update: converData here 
       converData(tempItem);
    

    And the convert function:

    public void converData(ObservableCollection<EventsHBTwo> allItem)
            {
    
                AllItems = new ObservableCollection<EventsHB>();
    
                EventsHB julyGroup = new EventsHB() { month = "July" };
                EventsHB juneGroup = new EventsHB() { month = "June" };
    
                foreach (var item in allItem)
                {
                    EventsHBTwo hb = item;
                    if (hb.month == "July")
                    {
                        julyGroup.Add(hb.eventTO);
                    }
                    else if (hb.month == "June")
                    {
                        juneGroup.Add(hb.eventTO);
                    }
                }
    
                //at last, add them to All items.
                AllItems.Add(julyGroup);
                AllItems.Add(juneGroup);
            }
    

    Last in the xaml, add IsGroupingEnabled GroupShortNameBinding GroupDisplayBinding here:

    <ListView x:Name="MyEventsListview"
                          RefreshCommand="{Binding RefreshCommand}"
                          IsRefreshing="{Binding IsRefreshing}"
                          IsPullToRefreshEnabled="True"
                          HasUnevenRows="True"
                          ItemsSource="{Binding AllItems,Mode=TwoWay}"
                          BackgroundColor="White"
                          IsGroupingEnabled="True"
                          GroupDisplayBinding="{Binding month}"
                          GroupShortNameBinding="{Binding month}">
    

    And use startDate startTime directly instead of eventTO.startDate.

    I uploaded my sample here and you can check it: working-grouped-listView-xamarin.forms

    The best way to achieve this is to ask your service side to give you json like this:

    {"eventsHB":
        {july:[
    
            {"eventTO":{"calendarEventId":135,}}
    
            {"eventTO":{"calendarEventId":135,}}
    
            {"eventTO":{"calendarEventId":135,}}
    
            {"eventTO":{"calendarEventId":135,}}
        }
    
        {june:[
    
            {"eventTO":{"calendarEventId":135,}}
    
            {"eventTO":{"calendarEventId":135,}}
    
            {"eventTO":{"calendarEventId":135,}}
    
            {"eventTO":{"calendarEventId":135,}}
    
             ]
        }
        ...
    }