---
title: "Create a Sleek Contact Management App in .NET MAUI Using ListView and DataForm"
published_at: "2025-06-20T12:34:17+00:00"
modified_at: "2025-06-20T13:34:10+00:00"
url: "https://www.syncfusion.com/blogs/post/contact-app-maui-listview-dataform"
excerpt: "Build a contact management app with .NET MAUI using ListView and DataForm. Complete guide covering MVVM architecture, data binding, CRUD operations, filtering, and UX enhancements with code examples."
taxonomy_category:
  - ".NET MAUI"
  - "Cross-Platform Development"
  - "Data Form"
  - "ListView"
  - "Software Development"
taxonomy_post_tag:
  - ".NET"
  - ".NET MAUI"
  - "Cross-platform development"
  - "DataForm"
  - "ListView control"
---

# Create a Sleek Contact Management App in .NET MAUI Using ListView and DataForm

[Jayaleshwari N](https://www.syncfusion.com/blogs/author/jayaleshwarin)

![Create a Sleek Contact Management App in .NET MAUI Using ListView and DataForm](https://www.syncfusion.com/blogs/wp-content/uploads/2025/06/Create-a-Sleek-Contact-Management-App-in-.NET-MAUI-Using-ListView-and-DataForm.jpg)


**TL;DR:** Learn to build a complete contact management app with .NET MAUI using ListView and DataForm components. This guide covers MVVM architecture implementation, data binding, UI design, and essential features like adding, editing, deleting, and filtering contacts with grouping and enhanced user interactions.

Managing contacts efficiently is a common requirement in many applications. In this blog post, we’ll guide you through building a simple yet powerful contact management app using [ListView](https://www.syncfusion.com/maui-controls/maui-listview)
 and [DataForm](https://www.syncfusion.com/maui-controls/maui-dataform)
. These components make it easy to display, edit, and organize contacts while maintaining an intuitive user experience.

Combine a **ListView** to display the contact list and a ** DataForm** to add or edit contact details. With proper data binding, updates made in the DataForm will reflect immediately in the ListView, creating a dynamic and responsive app. Here we have the sections to handle:

- [Displaying Contacts with ListView](#Displaying)
- [Display contact in DataForm](#Display)
- [Adding and editing contacts](#Adding)

## Displaying contacts with ListView

When building a contact management app, one of the most critical features is presenting contact information in a clean and organized manner. **ListView** is a versatile control that simplifies displaying and managing lists, making it an ideal choice for showcasing contacts.

Let’s dive into the steps to display contacts in the ListView.

## Step 1: Implementing Model and ViewModel

Include the model class to handle the contact info properties and the **ViewModel** class to populate the binding collection property to show the contacts list in the [ListView](https://help.syncfusion.com/cr/maui/Syncfusion.Maui.ListView.SfListView.html)
.

### Creating a model

Create a data model to bind it to the control. In a new class file, create a simple data source, as shown in the code example below, and save it as a **ContactInfo.cs** file.

```
public class ContactInfo : INotifyPropertyChanged
{
    #region Fields

    private string? contactName = string.Empty;      
    private string? image = string.Empty;
    private string? contactNumber = string.Empty;        
    private string contactType = string.Empty;

    #endregion

    #region Constructor

    public ContactInfo()
    {

    }

    #endregion

    #region Public Properties

    [Display(Name = "Name")]
    public string? ContactName
    {
        get { return this.contactName; }
        set
        {
            this.contactName = value;
            RaisePropertyChanged("ContactName");
        }
    }

    [Display(AutoGenerateField = false)]
    public string? ContactImage
    {
        get { return this.image; }
        set
        {
            if (value != null)
            {
                this.image = value;
                this.RaisePropertyChanged("ContactImage");
            }
        }
    }

    [Display(Name = "Number")]
    public string? ContactNumber
    {
        get
        {
            return this.contactNumber;
        }
        set
        {
            if (value != null)
            {
                this.contactNumber = value;
                this.RaisePropertyChanged("ContactNumber");
            }
        }
    }

    [Display(Name = "Type")]
    public string ContactType
    {
        get { return contactType; }
        set
        {
            this.contactType = value;
            RaisePropertyChanged("ContactType");
        }
    }

    #endregion

    #region INotifyPropertyChanged implementation

    public event PropertyChangedEventHandler? PropertyChanged;

    private void RaisePropertyChanged(String name)
    {
        if (PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(name));
    }

    #endregion
}
```

### Creating a ViewModel

Create a model repository class with the **ContactInfo** collection property, initialize it with the required number of data objects in a new class file as shown in the code example below, and save it as ** ViewModel.cs** file.

```
public class ViewModel : INotifyPropertyChanged
{
    #region Fields

    private ObservableCollection<ContactInfo>? contactsInfo;

    #endregion

    #region Constructor

    public ViewModel()
    {
        GenerateSource(100);
    }

    #endregion

    #region Properties

    public ObservableCollection<ContactInfo>? ContactsInfo
    {
        get { return contactsInfo; }
        set
        {
            this.contactsInfo = value;
            OnPropertyChanged(nameof(contactsInfo));
        }
    }

    #endregion

    #region ItemSource

    public void GenerateSource(int count)
    {
        ContactsInfoRepository contactRepository = new();
        contactsInfo = contactRepository.GetContactDetails(count);
    }

    #endregion

    #region Interface Member

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string name)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(name));
    }

    #endregion
}
```

## Step 2: Designing the UI

Create the UI to show the contact list using the **.NET MAUI ListView**. Install the necessary package to use the control in the application.

**Note:** For more details, refer to the [.NET MAUI ListView](https://help.syncfusion.com/maui/listview/getting-started)
documentation.

### Binding data to the ListView

The **BindingContext** for the main page is set with a ViewModelto bind properties and commands to the ListView.

```
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:syncfusion="clr-namespace:Syncfusion.Maui.ListView;assembly=Syncfusion.Maui.ListView"
             xmlns:local="clr-namespace:ListViewMAUI"
             x:Class="ListViewMAUI.MainPage">
    <ContentPage.BindingContext>
        <local:ViewModel/>
    </ContentPage.BindingContext>
</ContentPage>
```

To populate the ListView, bind the item collection from the BindingContext to the [SfListView.ItemsSource](https://help.syncfusion.com/cr/maui/Syncfusion.Maui.ListView.SfListView.html#Syncfusion_Maui_ListView_SfListView_ItemsSource)
 property.

The code example below demonstrates how to bind the previously created collection to the **SfListView.ItemsSource** property:

```
<syncfusion:SfListView x:Name="listView" 
                       ItemsSource="{Binding ContactsInfo}"/>
```

### Defining the item template

To define the [ItemTemplate](https://help.syncfusion.com/cr/maui/Syncfusion.Maui.ListView.SfListView.html#Syncfusion_Maui_ListView_SfListView_ItemTemplate)
 for a ListView that displays contacts, you can create a custom template that includes controls like labels for displaying contact details and an image to show the contact’s image.

```
<syncfusion:SfListView x:Name="listView" 
                       ItemsSource="{Binding ContactsInfo}">
    <syncfusion:SfListView.ItemTemplate>
        <DataTemplate>
            <Grid x:Name="grid" RowSpacing="0" HeightRequest="50" BackgroundColor="White">
                <Image Grid.Column="0" Source="{Binding ContactImage}"/>
                <Label Grid.Column="1" Text="{Binding ContactName}" />
            </Grid>
        </DataTemplate>
    </syncfusion:SfListView.ItemTemplate>

</syncfusion:SfListView>
```

And the contacts will be grouped based on the **ContactName** property. The group header has been customized to show only the Key, names starting letter, just like the contacts app on mobile phones.

```
<syncfusion:SfListView.GroupHeaderTemplate>
    <DataTemplate>
        <StackLayout Orientation="Horizontal">
            <Label Text="{Binding Key}"
                   FontSize="20"
                   FontFamily="Roboto-Medium"
                   VerticalOptions="Center"
                   HorizontalOptions="Start"
                   WidthRequest="200"
                   Margin="20,0,0,0" />
        </StackLayout>
    </DataTemplate>
</syncfusion:SfListView.GroupHeaderTemplate>
```

By default, the key is the value of the property being grouped. For grouping names that start with the same letter, we use **KeySelector** for grouping.

```
public class SfListViewGroupingBehavior : Behavior<ContentPage>
{
    #region Fields

    private Syncfusion.Maui.ListView.SfListView ListView;

    #endregion

    #region Overrides
    protected override void OnAttachedTo(ContentPage bindable)
    {
        ListView = ListView = bindable.FindByName<Syncfusion.Maui.ListView.SfListView>("listView"); 
        ListView.DataSource.GroupDescriptors.Add(new GroupDescriptor()
        {
            PropertyName = "ContactName",
            KeySelector = (obj1) =>
            {
                var item = obj1 as ContactInfo;                    
                return (item is not null && (item.ContactName.Length > 0 ) ) ? item.ContactName[0].ToString() : "Empty";
            },
        });
        ListView.DataSource.SortDescriptors.Add(new SortDescriptor()
        {
            PropertyName = "ContactName",
        });
        base.OnAttachedTo(bindable);
    }
}
```

Behavior is added to the content page and accesses the ListView by the **FindByName** method. You can refer to the following code to assign the behavior class to the content page.

```
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ListViewMAUI"
             x:Class="ListViewMAUI.MainPage">

    <ContentPage.Behaviors>
        <local:SfListViewGroupingBehavior/>
    </ContentPage.Behaviors>

</ContentPage>
```

You can get the following output when you run the above code snippet.

![Contact list displayed in ListView](https://www.syncfusion.com/blogs/wp-content/uploads/2025/05/Contact-list-display-in-ListView.png)

Contact list displayed in ListView

Each contact can be expanded to show contact options like UI with calling, messaging, video calling, and contact information. This is achieved using the tap command in the **ViewModel**.

```
public class ViewModel : INotifyPropertyChanged
{
    #region Fields

    private ContactInfo selectContact;
    private bool isReadOnly;

    #endregion

    #region Constructor

    public ViewModel()
    {
+
    }

    #endregion

    #region Properties

    public ContactInfo SelectedItem
    {
        get
        {
            return selectContact;
        }
        set
        {
            selectContact = value;
            OnPropertyChanged(nameof(SelectedItem));
        }
    }

    public bool IsVisible
    {
        get
        {
            return !IsReadOnly;
        }
    }

    public ObservableCollection<ContactOption> ContactOptions { get; set; }

    #endregion

    #region ItemSource

    public void GenerateSource(int count)
    {
        InitializeCommands();
        InitializeContactOptions();
    }

    #endregion

    #region  Commands
    public Command TapCommand { get; set; }

    private void InitializeCommands()
    {
        TapCommand = new Command(OnTapCommand);
    }

    private void InitializeContactOptions()
    {
        ContactOptions = new ObservableCollection<ContactOption>();
        ContactOptions.Add(new ContactOption() { ActionName = "Call", ActionIcon = "\ue763" });
        ContactOptions.Add(new ContactOption() { ActionName = "Message", ActionIcon = "\ue759" });
        ContactOptions.Add(new ContactOption() { ActionName = "Video", ActionIcon = "\ue76b" });
        ContactOptions.Add(new ContactOption() { ActionName = "Info", ActionIcon = "\ue719" });
    }

    private async void OnTapCommand(object eventArgs)
    {
        var tappedEventArgs = eventArgs as Syncfusion.Maui.ListView.ItemTappedEventArgs;
        if (tappedEventArgs != null)
        {
            SelectedItem = tappedEventArgs.DataItem as ContactInfo;
            if (SelectedItem == null)
                return;
            SelectedItem.IsExpanded = !SelectedItem.IsExpanded;

            if (!SelectedItem.IsExpanded)
                return;

            foreach(var contact in this.ContactsInfo)
                if(contact != SelectedItem)
                    contact.IsExpanded = !SelectedItem.IsExpanded;
        }
    }
}
```

Contact options are defined using the **ChipGroup** component. And it’s shown when you tap the list item using the ** IsVisible** property. You can find the ChipGroup definition here:

```
<syncfusion:SfListView x:Name="listView" Grid.Row=" AutoFitMode="DynamicHeight" ItemsSource="{Binding ContactsInfo}">                                   

    <syncfusion:SfListView.ItemTemplate>
        <DataTemplate>
            <Grid x:Name="grid" RowSpacing="0" HeightRequest="50"  BackgroundColor="White">
                <Grid Margin="56,0,0,0" IsVisible="{Binding IsExpanded, Mode=TwoWay}" >                              
                    <Label Text="{Binding ContactNumber}" FontSize="{OnPlatform Default=16,WinUI=14}" CharacterSpacing="0.5" VerticalOptions="Start"/>
                    <chip:SfChipGroup Grid.Row="1" 
                                      ItemHeight="40" 
                                      ChipCornerRadius="20" 
                                      ChipBackground="Transparent" 
                                      ChipStrokeThickness="0"      
                                      ChipPadding="10"  
                                      ChipClicked="SfChipGroup_ChipClicked"                                                                                  
                                      ItemsSource="{Binding Path=BindingContext.ContactOptions, Source={x:Reference listView}}">
                        <chip:SfChipGroup.ItemTemplate>
                            <DataTemplate>
                                <Label Text="{Binding ActionIcon}" VerticalOptions="Center" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" HorizontalOptions="Center" WidthRequest="40" FontFamily="MauiSampleFontIcon" TextColor="{StaticResource Primary}" FontSize="Medium">
                                </Label>
                            </DataTemplate>
                        </chip:SfChipGroup.ItemTemplate>
                    </chip:SfChipGroup>
                </Grid>
            </Grid>
        </DataTemplate>
    </syncfusion:SfListView.ItemTemplate>
</syncfusion:SfListView>
```

You can get the following output when you tap the list view item.

![Expanded contact item with options](https://www.syncfusion.com/blogs/wp-content/uploads/2025/05/Expanded-contact-item-with-options.png)

Expanded contact item

## Display contact in DataForm

DataForm displays the contact using the **DataObject** bound with the ViewModel’s ** SelectedItem** property. ** SelectedItem** will be updated when you tap the contact list.

```
<dataForm:SfDataForm x:Name="contactForm" 
                     DataObject="{Binding SelectedItem}" 
                     Grid.Row="1" 
                     IsReadOnly="{Binding IsReadOnly}" 
                     CommitMode="Manual" />
```

The **IsReadOnly** property determines whether we are just showing the contact or trying to edit it. When you tap on the show information chip, DataForm will be in read-only mode.

```
private void SfChipGroup_ChipClicked(object sender, EventArgs e)
{
    var chip = (sender as SfChip);
    var label = chip.Children[0] as Label;
    var action = (label.BindingContext as ContactOption).ActionName;
    var viewModel = this.BindingContext as ViewModel;
    if (("Info").Equals(action))
    {
        viewModel.SelectedItem = (sender as SfChip).BindingContext as ContactInfo;
        viewModel.OnShowContactCommand();
    }
}
```

On the **show contact command** method, DataForm will be loaded with the same bindingcontext.

```
internal async void OnShowContactCommand()
{
    IsReadOnly = true;
    var editPage = new ContactPage();
    editPage.BindingContext = this;
    await App.Current.MainPage.Navigation.PushAsync(editPage);
}
```

You will get the following output when you run the above code snippet.

![Contact List displayed in DataForm](https://www.syncfusion.com/blogs/wp-content/uploads/2025/05/Contact-List-displayed-in-DataForm.gif)

Contact details in DataForm

## Adding and editing contacts with DataForm

We use the add icon to create a contact using the DataForm with the bound property **SelectedItem** from the ViewModel. A new contact is created using the ** CreatedContactCommand**.

```
public class ViewModel : INotifyPropertyChanged
{
    #region Fields
    private ContactInfo selectContact;
    #endregion

    #region Properties

    public ContactInfo SelectedItem
    {
        get
        {
            return selectContact;
        }
        set
        {
            selectContact = value;
            OnPropertyChanged(nameof(SelectedItem));
        }
    }

    #endregion

    #region  Commands
    public Command CreateContactCommand { get; set; }

    private void InitializeCommands()
    {
        CreateContactCommand = new Command(OnCreateContact);
    }

    internal async void OnCreateContact()
    {
        SelectedItem = new ContactInfo();
        IsReadOnly = false;
        var editPage = new ContactPage();
        editPage.BindingContext = this;
        await App.Current.MainPage.Navigation.PushAsync(editPage);
    }
    #endregion
}
```

### Adding contact

The add icon is defined using a label and a font icon. The ViewModel’s **CreateContactCommand** is assigned to label gestures, creates a new contact, and shows the fields in DataForm to add the values.

```
<Label Text="&#xe754;"           
       VerticalOptions="Center"
       HorizontalOptions="Center"
       FontFamily="MauiSampleFontIcon"          
       TextColor="{StaticResource Primary}"        
       Grid.Column="1"
       FontSize="Medium" >
    <Label.GestureRecognizers>
        <TapGestureRecognizer Command="{Binding CreateContactCommand}"/>
    </Label.GestureRecognizers>
</Label>
```

You can see the following output when you click on the plus icon in the contact list page.

![Empty DataForm fields for adding a new contact](https://www.syncfusion.com/blogs/wp-content/uploads/2025/05/Empty-DataForm-fields-for-adding-a-new-contact-1.png)

Empty DataForm fields for adding a new contact

On this page, you can add the new contact to the list using the save button or discard the contact using the cancel button.

### Editing contact

You can edit the contact when you tap its information. When you tap on each contact, you can see the contact options.

You can edit the contact by setting the **IsReadOnly** property to false. Edited values will be committed only on save since we defined ** CommitMode** as manual for DataForm. The value will be committed using the ** Commit()** method.

```
contactForm.Commit();
```

Refer to the following image.

![Editable contact fields in DataForm](https://www.syncfusion.com/blogs/wp-content/uploads/2025/05/Editable-contact-fields-in-DataForm-1.gif)

Editable contact fields in DataForm

### Deleting contact

The tapped contact can be deleted using the **delete** icon in the DataForm page. The contact will be deleted from the list.

These edit, save, cancel, and delete icons are defined using **SfChipGroup**. You can find the code snippets here:

```
<chip:SfChipGroup HorizontalOptions="Center" 
                  IsVisible="{Binding IsVisible}"
                  ItemHeight="40" 
                  ChipCornerRadius="20" 
                  ChipBackground="Transparent" 
                  ChipStrokeThickness="0"      
                  ChipPadding="10"  
                  ChipClicked="OnChipClicked"                                                                               
                  ItemsSource="{Binding CommitOptions}">
    <chip:SfChipGroup.ItemTemplate>
        <DataTemplate>
            <HorizontalStackLayout>
                <Label Text="{Binding ActionIcon}" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" WidthRequest="40" FontFamily="MauiSampleFontIcon" TextColor="{StaticResource Primary}" FontSize="Medium"/>
                <Label Text="{Binding ActionName}" VerticalTextAlignment="Center" HorizontalTextAlignment="Start"  TextColor="{StaticResource Primary}"  FontFamily="Roboto-Regular"   FontSize="{OnPlatform Default=16,WinUI=14}" Margin="0,0,5,0"/>
            </HorizontalStackLayout>
        </DataTemplate>
    </chip:SfChipGroup.ItemTemplate>
</chip:SfChipGroup>
```

Based on the chip clicked, the associated action will be performed.

```
private void OnChipClicked(object sender, EventArgs e)
{
    var viewmodel = this.BindingContext as ViewModel;
    var chip = (sender as SfChip);
    var layout = chip.Children[0] as HorizontalStackLayout;
    var action = (layout.BindingContext as ContactOption).ActionName;
    if (string.IsNullOrEmpty(action))
        return;

    switch(action)
    {
        case "Edit":
            viewmodel.OnEditContactCommand();
            break;
        case "Delete":
            viewmodel.OnDeleteContactCommand();
            break;
        case "Save":
            viewmodel.OnSaveContact();
            contactForm.Commit();
            break;
        case "Cancel":
            viewmodel.OnCancelContact();
            break;
    }
}
```

### Add filtering

Creating a contact management app isn’t just about functionality; it’s about delivering a seamless and intuitive experience that makes managing contacts effortless and enjoyable. A well-thought-out user experience can significantly improve user satisfaction and engagement. Here’s how to enhance your contact management app.

Filtering is applied on the**TextChanged** event of the ** SearchTextBox**.

```
public class SfListViewGroupingBehavior : Behavior<ContentPage>
{
    #region Fields

    private Syncfusion.Maui.ListView.SfListView ListView;
    private SearchBar searchBar = null;

    #endregion

    #region Overrides
    protected override void OnAttachedTo(ContentPage bindable)
    {
        ListView = ListView = bindable.FindByName<Syncfusion.Maui.ListView.SfListView>("listView"); 
        searchBar = bindable.FindByName<SearchBar>("searchBar");
        searchBar.TextChanged += SearchBar_TextChanged;

        base.OnAttachedTo(bindable);
    }

    protected override void OnDetachingFrom(ContentPage bindable)
    {
        ListView = null;
        searchBar = null;
        searchBar.TextChanged -= SearchBar_TextChanged;
        base.OnDetachingFrom(bindable);
    }

    private void SearchBar_TextChanged(object sender, TextChangedEventArgs e)
    {
        searchBar = (sender as SearchBar);
        if (ListView.DataSource != null)
        {
            ListView.DataSource.Filter = FilterContacts;
            ListView.DataSource.RefreshFilter();
        }
        ListView.RefreshView();
    }
    private bool FilterContacts(object obj)
    {
        if (searchBar == null || searchBar.Text == null)
            return true;

        var contactInfo = obj as ContactInfo;
        return (contactInfo.ContactName.ToLower().Contains(searchBar.Text.ToLower()) || (contactInfo.ContactNumber.ToString()).ToLower().Contains(searchBar.Text.ToLower()));
    }

    #endregion
}
```

The behavior class is added to the content page. You can find the code snippet here:

```
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:syncfusion="clr-namespace:Syncfusion.Maui.ListView;assembly=Syncfusion.Maui.ListView"
             xmlns:chip="clr-namespace:Syncfusion.Maui.Core;assembly=Syncfusion.Maui.Core"
             xmlns:local="clr-namespace:ListViewMAUI"
             x:Class="ListViewMAUI.MainPage">

    <ContentPage.Behaviors>
        <local:SfListViewGroupingBehavior/>
    </ContentPage.Behaviors>
</ContentPage>
```

Refer to the following output.

![Contact Management App with ListView and DataForm](https://www.syncfusion.com/blogs/wp-content/uploads/2025/05/Contact-Management-App-with-ListView-and-DataForm.gif)

Contact Management App with ListView and DataForm

## GitHub reference

For more details, refer to the [GitHub demo.](https://github.com/SyncfusionExamples/Creating-a-Contact-Management-App-with-ListView-and-DataForm.git)


## FAQs

**Q1: How do I implement contact grouping by first letter in the ListView?**

Use the **KeySelector** property in ** GroupDescriptor** to group contacts by their first letter. Create a behavior class that adds a ** GroupDescriptor** with ** PropertyName = “ContactName”** and a ** KeySelector** that returns ** item.ContactName[0].ToString()**. This will automatically group contacts alphabetically, like a typical phone contacts app.

**Q2: Can I edit contacts directly in the ListView, or need a separate page?**

The app uses a separate page with a **DataForm** for editing contacts. When you tap a contact, it expands to show action options (Call, Message, Video, Info). Tapping “Info” navigates to a dedicated page with ** DataForm** bound to the ** SelectedItem** property, where you can view, edit, or delete the contact using the IsReadOnly property to control the mode.

**Q3: How does the filtering feature work when searching for contacts?**

Filtering is implemented using a **SearchBar** with a ** TextChanged** event handler in a behavior class. The filter method checks if the contact name or phone number contains the search text (case-insensitive). The ListView’s ** DataSource.Filter** property is set to this ** filter** method, and ** RefreshFilter()** is called to update the list and ** RefreshView()** to display in real-time as you type.

**Q4: What’s the difference between Manual and Auto commit modes in DataForm?**

The app uses **CommitMode=”Manual”** for ** DataForm**, which means changes aren’t automatically saved to the data source. You must explicitly call ** contactForm.Commit()** when the user taps the Save button. This gives you control over when changes are applied and allows users to cancel edits without affecting the original data, providing a better user experience for contact management.

## Conclusion

Building a contact management app using [ListView](https://www.syncfusion.com/maui-controls/maui-listview)
 and [DataForm](https://www.syncfusion.com/maui-controls/maui-dataform)
 in .NET MAUI is efficient and customizable. With features like grouping, searching, editing, and dynamic data binding, you can deliver a seamless user experience. This approach simplifies UI development and ensures scalability and maintainability for real-world applications.

For existing Syncfusion® customers, the newest version of Essential Studio® is available from the [license and downloads](https://www.syncfusion.com/account)
 page. If you are not a customer, try our 30-day [free trial](https://www.syncfusion.com/downloads)
 to check out these new features.

If you need a new widget for the Flutter framework or new features in our existing widgets, you can contact us through our [support forums](https://www.syncfusion.com/forums)
, [support portal](https://support.syncfusion.com/)
, or [feedback portal](https://www.syncfusion.com/feedback)
. As always, we are happy to assist you!

## Related Blogs



[Create a Beautiful Photo Gallery Using .NET MAUI Tab View and ListView](https://www.syncfusion.com/blogs/post/dotnet-maui-photo-gallery)



[Build a Stunning Music Track UI Using .NET MAUI ListView](https://www.syncfusion.com/blogs/post/build-music-track-ui-in-dotnet-maui)



[Integrating AI-Powered Smart Paste in .NET MAUI DataForm for Easy Data Entry](https://www.syncfusion.com/blogs/post/ai-powered-smart-paste-maui-dataform)



[Efficiently Handle Large Datasets with Seamless Pagination in .NET MAUI ListView](https://www.syncfusion.com/blogs/post/net-maui-listview-pagination)
