Add Contact Features in 4 Lines of Code with Xamarin.Essentials

James Montemagno

Integrating contact functionality has been a common task that I have been asked to develop for mobile apps over the years. This has ranged from a full contacts directory to simple contact information inside an app. Most requested features include the ability to call the contact, send an sms or email, and navigate to a location. In the past, I would have to implement several native APIs myself or install several libraries that could provide the functionality. Today, with Xamarin.Essentials all of this functionality is available in a single library and can be implemented in just 4 lines of code! So, let’s build a contacts application with Xamarin.Essentials and Xamarin.Forms.

Animation of a contact application built with Xamarin

The Contact

The first thing to do is define the Contact class. This will have all of the information that is needed when using the Xamarin.Essentials APIs. This includes a phone number, email, and address.

public class Contact
{
    public string Name { get; set; }
    public string PhoneNumber { get; set; }
    public string Email { get; set;  }
    public string Address { get; set;  }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
}

Contact User Interface

There are a lot of ways to present contact information and for our example we can use a grid to display all of the information. We can use ImageButton for each item to enable users to take action. Each Commandis bound to a method that will be called from the ViewModel that I will outline next.

<Grid RowSpacing="8">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="44"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="44"/>
    </Grid.ColumnDefinitions>

    <!--Phone & SMS-->
    <ImageButton Source="phone.png" Grid.Row="0" VerticalOptions="Center"
                    Command="{Binding PhoneCommand}" BackgroundColor="Transparent" />
    <Label Grid.Column="1" Grid.Row="0"
            VerticalOptions="Center"
            Text="{Binding Contact.PhoneNumber}"/>
    <ImageButton Source="sms.png" Grid.Row="0" Grid.Column="2" VerticalOptions="Center"
                    Command="{Binding SmsCommand}" BackgroundColor="Transparent"/>
    
    <!--Email-->
    <ImageButton Source="email.png" Grid.Row="1"  VerticalOptions="Center"
                    Command="{Binding EmailCommand}" BackgroundColor="Transparent"/>

    <Label Grid.Column="1" Grid.Row="1"
            VerticalOptions="Center"
            Text="{Binding Contact.Email}"/>

    <!--Address-->
    <ImageButton Source="navigate.png" Grid.Row="2" VerticalOptions="Center"
                    Command="{Binding NavigateCommand}" BackgroundColor="Transparent"/>

    <StackLayout Grid.Column="1" Grid.Row="2" VerticalOptions="Center">
        <Label Text="{Binding Contact.Address}"/>
        <Label>
            <Label.FormattedText>
                <FormattedString>
                    <Span Text="{Binding Contact.City}"/>
                    <Span Text=" "/>
                    <Span Text="{Binding Contact.State}"/>
                    <Span Text=", "/>
                    <Span Text="{Binding Contact.ZipCode}"/>
                </FormattedString>
            </Label.FormattedText>
        </Label>
    </StackLayout>
            
</Grid>

This will give us a very pretty user interface for our contact.

User interface for a contact card

Phone Dialer, Sms, Email, and Navigation!

Each Command that is bound in the user interface has a method that will be executed when the button is clicked. Each method uses a Xamarin.Essentials API to execute native functionality from a single line of code! Here is the full ViewModel from the sample app:

public class ContactViewModel
{
    public Command SmsCommand { get; }
    public Command EmailCommand { get; }
    public Command PhoneCommand { get; }
    public Command NavigateCommand { get; }

    public Contact Contact { get; }

    public ContactViewModel(Contact contact)
    {
        Contact = contact;
    }

    public ContactViewModel()
    {
        Contact = new Contact
        {
            Name = "James Montemagno",
            Address = "Microsoft Building 18",
            City = "Redmond",
            State = "WA",
            ZipCode = "98052",
            Email = "motz@microsoft.com",
            PhoneNumber = "555-555-5555"
        };

        SmsCommand = new Command(async () => await ExecuteSmsCommand());
        EmailCommand = new Command(async () => await ExecuteEmailCommand());
        PhoneCommand = new Command(ExecutePhoneCommand);
        NavigateCommand = new Command(async () => await ExecuteNavigateCommand());
    }

    async Task ExecuteSmsCommand()
    {
        try
        {
            await Sms.ComposeAsync(new SmsMessage(string.Empty, Contact.PhoneNumber));
        }
        catch (Exception ex)
        {
            ProcessException(ex);
        }
    }

    async Task ExecuteEmailCommand()
    {
        try
        {
            await Email.ComposeAsync(string.Empty, string.Empty, Contact.Email);
        }
        catch (Exception ex)
        {
            ProcessException(ex);
        }
    }

    void ExecutePhoneCommand()
    {
        try
        {
            PhoneDialer.Open(Contact.PhoneNumber);
        }
        catch (Exception ex)
        {
            ProcessException(ex);
        }
    }

    async Task ExecuteNavigateCommand()
    {
        try
        {
            await Map.OpenAsync(new Placemark
            {
                Thoroughfare = Contact.Address,
                Locality = Contact.City,
                AdminArea = Contact.State,
                PostalCode = Contact.ZipCode
            });
        }
        catch (Exception ex)
        {
            ProcessException(ex);
        }
    }

    void ProcessException(Exception ex)
    {
        if (ex != null)
            Application.Current.MainPage.DisplayAlert("Error", ex.Message, "OK");
    }
}

Note here that on each platform we are wrapping the method call in a Try/Catch block. This is important in case the feature is not available on the specific device. Beyond that, we are done! With just 4 tiny lines of code we have integrated tons of great native functionality into our contacts app!

Learn More

Be sure to browse through the full Xamarin.Essentials documentation for setup instructions and API information. Subscribe to the Xamarin Developers YouTube channel and browse through theXamarin.Essentials API of the Week series that feature short videos outlining a single API. Looking for more blogs on Xamarin.Essentials? Be sure to checkout the blog archive that is filled with great posts.

Find more awesome information on cross-platform development with Xamarin. If you are looking to add a backend to your app take a look at App Center Data & Azure Cosmos DB. Also, checkout the full GeoContacts Sample on GitHub.

Finally, you can can grab the source code for this blog on GitHub and try it today!

2 comments

Discussion is closed. Login to edit/delete existing comments.

  • Eric 0

    Awesome

  • favour emmanuel 0

    Excellent

Feedback usabilla icon