Exercise: Create the phone number translator app
In this exercise, you construct the UI for the phone dialer app and implement the logic behind this UI.
You build a UI that takes advantage of the UI capabilities of .NET MAUI (Multi-platform Application User Interface) and the .NET MAUI Essentials package to dial the phone.
The app lets the user type text into an input field, and translates that text to numeric digits. It uses the letters that show up on a telephone keypad as the basis for translation. For example, the letters cab translate to 222 because the digit 2 has all three letters a, b, and c.
You continue with the Phoneword solution you created in the previous exercise.
Add a new C# source file to the app
Open the Phoneword solution in Visual Studio if you don't already have it open.
In the Solution Explorer window, right-click the Phoneword project, select Add, and select Class.
In the Add New Item dialog box, name the class file PhonewordTranslator.cs, then select Add.
Add the translation logic
Replace the content of the class file with the following code and save the file. The static method ToNumber
in the PhonewordTranslator
class translates the number from alphanumeric text into a regular numeric phone number.
using System.Text;
namespace Core;
public static class PhonewordTranslator
{
public static string ToNumber(string raw)
{
if (string.IsNullOrWhiteSpace(raw))
return null;
raw = raw.ToUpperInvariant();
var newNumber = new StringBuilder();
foreach (var c in raw)
{
if (" -0123456789".Contains(c))
newNumber.Append(c);
else
{
var result = TranslateToNumber(c);
if (result != null)
newNumber.Append(result);
// Bad character?
else
return null;
}
}
return newNumber.ToString();
}
static bool Contains(this string keyString, char c)
{
return keyString.IndexOf(c) >= 0;
}
static readonly string[] digits = {
"ABC", "DEF", "GHI", "JKL", "MNO", "PQRS", "TUV", "WXYZ"
};
static int? TranslateToNumber(char c)
{
for (int i = 0; i < digits.Length; i++)
{
if (digits[i].Contains(c))
return 2 + i;
}
return null;
}
}
Create the UI
Open the MainPage.xaml file in the Phoneword project.
Remove the
ScrollView
control and its contents, leaving just theContentPage
control:<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Phoneword.MainPage"> </ContentPage>
Add a
VerticalStackLayout
control with vertical orientation and a spacing of 15 units and padding of 20 units to the ContentPage:<ContentPage ... > <VerticalStackLayout Spacing="15" Padding="20"> </VerticalStackLayout> </ContentPage>
Add a
Label
control to the StackLayout:<ContentPage ... > <VerticalStackLayout ...> <Label Text = "Enter a Phoneword" FontSize ="20"/> </VerticalStackLayout> </ContentPage>
Add an
Entry
control to the StackLayout, below the label. AnEntry
control provides a text box into which the user can enter data. In this code, the propertyx:Name
gives the control a name. You reference this control in the code for the app later:<ContentPage ... > <VerticalStackLayout ...> <Label .../> <Entry x:Name = "PhoneNumberText" Text = "1-555-NETMAUI" /> </VerticalStackLayout> </ContentPage>
Add two
Button
controls to the VerticalStackLayout, after the Entry control. Both buttons currently do nothing, and the second is disabled initially. You add the code to handle theClicked
event for these two buttons in the next task:<ContentPage ... > <VerticalStackLayout ...> <Label .../> <Entry ... /> <Button x:Name = "TranslateButton" Text = "Translate" Clicked = "OnTranslate"/> <Button x:Name = "CallButton" Text = "Call" IsEnabled = "False" Clicked = "OnCall"/> </VerticalStackLayout> </ContentPage>
Respond to the TranslateButton button tap
In the Solution Explorer window, expand the MainPage.xaml entry and open the MainPage.xaml.cs code-behind file.
In the
MainPage
class, remove thecount
variable and theOnCounterClicked
method. The class should look like this:namespace Phoneword; public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); } }
Add the
translatedNumber
string variable and the followingOnTranslate
method to theMainPage
class, after the constructor. TheOnTranslate
method retrieves the phone number from theText
property of theEntry
control and passes it to the staticToNumber
method of thePhonewordTranslator
class that you created earlier.public partial class MainPage : ContentPage { ... string translatedNumber; private void OnTranslate(object sender, EventArgs e) { string enteredNumber = PhoneNumberText.Text; translatedNumber = Core.PhonewordTranslator.ToNumber(enteredNumber); if (!string.IsNullOrEmpty(translatedNumber)) { // TODO: } else { // TODO: } } }
Note
You fill in the missing TODO bits of this code in the next step.
In the
OnTranslate
method, add code to change theText
property of the Call button to append the successfully translated phone number. You can use the value you stored in the translatedNumber field. Also, enable and disable the button based on the successful translation. For example, ifTranslateNumber
returned null, disable the button, but if it was successful, enable it.private void OnTranslate(object sender, EventArgs e) { string enteredNumber = PhoneNumberText.Text; translatedNumber = Core.PhonewordTranslator.ToNumber(enteredNumber); if (!string.IsNullOrEmpty(translatedNumber)) { CallButton.IsEnabled = true; CallButton.Text = "Call " + translatedNumber; } else { CallButton.IsEnabled = false; CallButton.Text = "Call"; } }
Create the event method for the CallButton button
Add the
OnCall
event handling method to the end of theMainPage
class. This method makes use of asynchronous operations, so mark it asasync
:public partial class MainPage : ContentPage { ... async void OnCall(object sender, System.EventArgs e) { } }
In the
OnCall
method, prompt the user, by using the Page.DisplayAlert method, to ask if they'd like to dial the number.The parameters to
DisplayAlert
are a title, a message, and two strings used for the Accept and Cancel button text. It returns a Boolean indicating whether the Accept button was pressed to dismiss the dialog box.async void OnCall(object sender, System.EventArgs e) { if (await this.DisplayAlert( "Dial a Number", "Would you like to call " + translatedNumber + "?", "Yes", "No")) { // TODO: dial the phone } }
Test the application
In the Visual Studio toolbar, select the Windows Machine profile and start debugging.
Tap the Translate button to convert the default text to a valid phone number. The caption on the Call button should change to Call 1-555-6386284:
Tap the Call button. Verify that a prompt appears asking you to confirm the operation. Select No.
Return to Visual Studio and stop debugging.
Dial the phone number
In the MainPage.xaml.cs code-behind file, edit the OnCall method and replace the TODO comment with the following
try/catch
blocks:async void OnCall(object sender, System.EventArgs e) { if (await this.DisplayAlert( "Dial a Number", "Would you like to call " + translatedNumber + "?", "Yes", "No")) { try { if (PhoneDialer.Default.IsSupported) PhoneDialer.Default.Open(translatedNumber); } catch (ArgumentNullException) { await DisplayAlert("Unable to dial", "Phone number was not valid.", "OK"); } catch (Exception) { // Other error has occurred. await DisplayAlert("Unable to dial", "Phone dialing failed.", "OK"); } } }
The PhoneDialer class in the Microsoft.Maui.ApplicationModel.Communication namespace provides an abstraction of the phone dialing functionality (and others) for the Windows, Android, iOS (and iPadOS), and macOS platforms. The static Open method attempts to use the phone dialer to call the number provided as the parameter.
The following steps show how to update the Android application manifest to enable Android to use the phone dialer. Windows, iOS, and MacCatalyst, applications follow the same general principle, except that you specify a different capability in the manifest depending on the operating system.
In the Solution Explorer window, expand the Platforms folder, expand the Android folder, right-click the AndroidManifest.xml file, and select Open with > Automatic Editor Selector (XML). Select OK.
Add the following XML snippet inside the manifest node, after the existing content for this node.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"> ... <queries> <intent> <action android:name="android.intent.action.DIAL" /> <data android:scheme="tel"/> </intent> </queries> </manifest>
Save the file.
In the Visual Studio toolbar, select the Android Emulators/Pixel 3a - API 30 (or similar) profile and start debugging.
When the app appears in the emulator (it can take a few minutes), enter a phone number (or accept the default) select Translate, then select Call.
In the Dial a Number alert, select Yes. Verify that the Android phone dialer appears with the number you provided in the app.
Return to Visual Studio and stop debugging.
Summary
In this exercise, you added a custom UI to your application by using pages and views. You also added support for placing a call by using platform-specific APIs available in Android.