Assume your application needs to display a list of tourist attractions in a city on a vertical list based on the city selected from a horizontal list. Here comes the Syncfusion .NET MAUI ListView to help you easily implement this in your .NET MAUI application.
The Syncfusion .NET MAUI ListView control is a list-like interface that renders a set of data in vertical and horizontal orientation with easy customization.
By customizing the Orientation property of the .NET MAUI ListView, you can easily configure the ListView to be horizontal or vertical.
Let’s get started with the development of this application.
Data population for a vertical and horizontal list
As we know, the .NET MAUI ListView is a data-bound control, and we must create a data model to bind to the ListView.
Creating a data model
Create a model class to hold the data values, such as the place’s name, image, and collection, which holds data for the vertical list.
Refer to the following code example.
public class PlaceInfo : INotifyPropertyChanged { #region Fields private string? name; private string? description; private ImageSource? image; private ObservableCollection<PlaceInfo> touristPlaces; #endregion #region Constructor public PlaceInfo() { } #endregion #region Properties public string? Name { get { return name; } set { name = value; OnPropertyChanged("Name"); } } public string? Description { get { return description; } set { description = value; OnPropertyChanged("Description"); } } public ImageSource? Image { get { return image; } set { image = value; OnPropertyChanged("Image"); } } public ObservableCollection<PlaceInfo> TouristPlaces { get { return touristPlaces; } set { touristPlaces = value; OnPropertyChanged("TouristPlaces"); } } #endregion #region Interface Member public event PropertyChangedEventHandler? PropertyChanged; public void OnPropertyChanged(string name) { if (this.PropertyChanged != null) this.PropertyChanged(this, new PropertyChangedEventArgs(name)); } #endregion }
Populate model collection in ViewModel
Create an ObservableCollection of PlaceInfo named Places to hold the data for the horizontal ListView. Each PlaceInfo will have a collection of PlaceInfo named TouristPlaces, which holds data for the vertical list to show the travel places.
Refer to the following code.
public class ListViewOrientationViewModel : INotifyPropertyChanged { #region Fields private ObservableCollection<PlaceInfo>? places; private PlaceInfo selectedItem; #endregion #region Constructor public ListViewOrientationViewModel() { var placesRepository = new PlaceInfoRepository(); Places = placesRepository.GeneratePlaces(); SelectedItem = Places[0]; } #endregion #region Properties public PlaceInfo SelectedItem { get { return selectedItem; } set { selectedItem = value; OnPropertyChanged("SelectedItem"); } } public ObservableCollection<PlaceInfo>? Places { get { return places; } set { this.places = value; OnPropertyChanged("Places"); } } #endregion #region INotifyPropertyChanged public event PropertyChangedEventHandler? PropertyChanged; private void OnPropertyChanged(string name) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(name)); } #endregion }
Now, bind the ViewModel’s Places collection to the horizontal ListView control on the XAML page.
<ContentPage x:Class="ListViewMaui.HorizontalOrientation" xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:ListViewMaui" xmlns:ListView="clr-namespace:Syncfusion.Maui.ListView;assembly=Syncfusion.Maui.ListView" BackgroundColor="White"> <ContentPage.BindingContext> <local:ListViewOrientationViewModel x:Name="viewModel"/> </ContentPage.BindingContext> <ListView:SfListView x:Name="listView" Grid.Row="1" ItemsSource="{Binding Places}" Orientation="Horizontal"> </ListView:SfListView> </ContentPage.Content> </ContentPage>
Defining horizontal ListView’s ItemTemplate
Once the ItemsSource is bound, the ListView control will display only the business objects (like PlaceInfo) as the content of the ListView items. We must update them by defining the ItemTemplate.
By defining the ItemTemplate, you can easily set custom views to display the data items.
Refer to the following code.
<ListView:SfListView x:Name="listView" Grid.Row="1" ItemsSource="{Binding Places}" ScrollBarVisibility="Never" SelectionMode="Single" Orientation="Horizontal" SelectionBackground="Transparent" ItemSize="{OnPlatform Android=120,Default=130}" Margin="8,0,0,0" HeightRequest="180" SelectedItem="{Binding SelectedItem}"> <ListView:SfListView.ItemTemplate> <DataTemplate> <Grid Margin="8,0,8,0"> <Grid.RowDefinitions> <RowDefinition Height="130"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Border Padding='{OnPlatform UWP="-5,-5,5,5"}' Stroke="#FFFDFD" StrokeThickness="6" HorizontalOptions="Center"> <Border.StrokeShape> <RoundRectangle CornerRadius="6"/> </Border.StrokeShape> <Image Grid.Row="0" Source="{Binding Image}" HeightRequest="130" WidthRequest="110" Aspect="Fill" Margin='{OnPlatform MacCatalyst=-3,iOS=-3}'/> </Border> <Label Grid.Row="1" Text="{Binding Name}" LineBreakMode="WordWrap" HorizontalTextAlignment="Center" HorizontalOptions="Center" VerticalTextAlignment="Center" FontFamily="Roboto-Regular" VerticalOptions="Center" HeightRequest="40" WidthRequest="110" TextColor="#99000000" FontSize="14"> </Label> </Grid> </DataTemplate> </ListView:SfListView.ItemTemplate> <ListView:SfListView.SelectedItemTemplate> <DataTemplate> <Grid Margin="8,0,8,0"> <Grid.RowDefinitions> <RowDefinition Height="130"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Border Padding='{OnPlatform UWP="-5,-5,5,5"}' Stroke="#1899EF" StrokeThickness="6" HorizontalOptions="Center"> <Border.StrokeShape> <RoundRectangle CornerRadius="6"/> </Border.StrokeShape> <Image Grid.Row="0" Source="{Binding Image}" HeightRequest="130" WidthRequest="110" Aspect="Fill" Margin='{OnPlatform MacCatalyst=-3,iOS=-3}'/> </Border> <Label Grid.Row="1" Text="{Binding Name}" LineBreakMode="WordWrap" HorizontalTextAlignment="Center" HorizontalOptions="Center" VerticalTextAlignment="Center" FontFamily="Roboto-Regular" VerticalOptions="Center" HeightRequest="40" WidthRequest="110" TextColor="#99000000" FontSize="14"> </Label> </Grid> </DataTemplate> </ListView:SfListView.SelectedItemTemplate> </ListView:SfListView>
Now the application will look like the following screenshot.
Data binding for vertical ListView
Now, selecting a city from the horizontal list will display the list of travel destinations by changing the ViewModel’s SelectedItem, which is bound to the horizontal ListView’s SelectedItem by using the bound property ItemsSource in the vertical ListView.
<ListView:SfListView x:Name="verticalListView" Grid.Row="3" ItemsSource="{Binding Path=SelectedItem.TouristPlaces, Source={x:Reference listView}}" ItemSize="60" ItemSpacing="16,8,16,8" SelectionMode="None"/>
Defining vertical ListView’s ItemTemplate
Here, we are showing the details of travel places by using their name, description, and image in custom views defined within the ItemTemplate property.
<ListView:SfListView x:Name="verticalListView" Grid.Row="3" ItemsSource="{Binding Path=SelectedItem.TouristPlaces, Source={x:Reference listView}}" ItemSize="60" ItemSpacing="16,8,16,8" SelectionMode="None"> <ListView:SfListView.ItemTemplate> <DataTemplate> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="76"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Frame HorizontalOptions="Start" CornerRadius="3" IsClippedToBounds="True" Padding="0" Margin="0" HasShadow="False" HeightRequest="60" WidthRequest="60"> <Image Grid.Column="0" HorizontalOptions="Start" Source="{Binding Image}" Aspect="Fill" HeightRequest="60" WidthRequest="60"/> </Frame> <Grid Grid.Column="1" VerticalOptions="Center"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Label Grid.Row="0" Text="{Binding Name}" FontSize="14" TextColor="#666666" FontFamily="Roboto-Regular" CharacterSpacing="0.25"/> <Label Grid.Row="1" Text="{Binding Description}" FontSize="14" FontFamily="Roboto-Regular" TextColor="#DE000000" LineBreakMode="WordWrap" CharacterSpacing="0.15" Margin="0,5,0,0"/> </Grid> </Grid> </DataTemplate> </ListView:SfListView.ItemTemplate> </ListView:SfListView>
After executing this code example, we will get output like in the following GIF image. Tapping on the items in the horizontal ListView dynamically updates the content of the vertical ListView.
Resources
For more details, refer to the complete sample of Travel Place Listing UI in .NET MAUI in the GitHub repository.
Conclusion
Thanks for reading! I hope you now have a good idea of how to use the .NET MAUI ListView to display tourist places in a vertical list based on the city selected from a horizontal list. Try creating this sample project and share your feedback in the comment section below.
For questions, contact us through our support forum, support portal, or feedback portal. We are always happy to assist you!
Related blogs
- Create Group Chat Profile View in .NET MAUI App
- Replicating an Immersive UI in .NET MAUI
- Learn Performing Animation in .NET MAUI: Part 1
- Add Busy Notifications to Your .NET MAUI Application