練習:建立電話號碼轉譯器應用程式

已完成

在本練習中,您會建構手機撥號應用程式的 UI,並實作此 UI 背後的邏輯。

您可以建置 UI,利用 .NET MAUI (多平台應用程式使用者介面) 和 .NET MAUI Essentials 套件的 UI 功能來撥打電話。

此應用程式可讓使用者在輸入欄位中輸入文字,並將該文字轉譯成數字。 它會使用電話鍵台上顯示的字母作為轉譯基礎。 例如,位數 2 有 a、b、c 這三個字母,因此會將字母 cab 轉譯成 222

您將使用在前一個練習中建立的 Phoneword 解決方案來繼續進行操作。

將新的 C# 來源檔案新增至應用程式

  1. 如果您尚未在 Visual Studio 中開啟 Phoneword 解決方案,請開啟它。

  2. 在 [方案總管] 視窗中,以滑鼠右鍵按一下 [Phoneword] 專案,選取 [新增],然後選取 [類別]

  3. 在 [新增項目] 對話方塊中,將類別檔案命名為 [PhonewordTranslator.cs],然後選取 [新增]

    [新增項目] 對話方塊的螢幕擷取畫面。名為類別檔案 PhonewordTranslator.cs 的使用者

新增轉譯邏輯

以下列程式碼取代類別檔案的內容,並儲存檔案。 PhonewordTranslator 類別中的靜態方法 ToNumber 方法會將號碼由英數字元文字轉譯成一般的數字電話號碼。

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;
    }
}

建立 UI

  1. 開啟 Phoneword 專案中的 MainPage.xaml 檔案。

  2. 移除 ScrollView 控制項及其內容,只保留 ContentPage 控制項:

    <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Phoneword.MainPage">
    
    </ContentPage>
    
  3. VerticalStackLayout 控制項以垂直方向、間距 15 個單位及邊框間距 20 個單位的方式新增至 ContentPage:

    <ContentPage ... >
        <VerticalStackLayout Spacing="15" Padding="20">
    
        </VerticalStackLayout>
    </ContentPage>
    
  4. 新增控制項 Label 至 StackLayout:

    <ContentPage ... >
        <VerticalStackLayout ...>
            <Label Text = "Enter a Phoneword"
                   FontSize ="20"/>
        </VerticalStackLayout>
    </ContentPage>
    
  5. 新增控制項 Entry 至 StackLayout,位於標籤下方。 控制項 Entry 提供了一個可讓使用者輸入資料的文字方塊。 在此程式碼中,屬性 x:Name 會命名控制項。 您稍後會於應用程式的程式碼中參考此控制項:

    <ContentPage ... >
        <VerticalStackLayout ...>
            <Label .../>
            <Entry x:Name = "PhoneNumberText"
                   Text = "1-555-NETMAUI" />
        </VerticalStackLayout>
    </ContentPage>
    
  6. 在 Entry 控制項之後,新增兩個 Button 控制項至 VerticalStackLayout。 目前這兩個按鈕不會有任何動作,且第二個按鈕在一開始的時候會處於停用狀態。 您會在下一個工作中新增這兩個按鈕來處理 Clicked 事件所需的程式碼:

    <ContentPage ... >
        <VerticalStackLayout ...>
            <Label .../>
            <Entry ... />
            <Button x:Name = "TranslateButton"
                    Text = "Translate"
                    Clicked = "OnTranslate"/>
            <Button x:Name = "CallButton"
                    Text = "Call"
                    IsEnabled = "False"
                    Clicked = "OnCall"/>
        </VerticalStackLayout>
    </ContentPage>
    

回應 [TranslateButton] 按鈕點選

  1. 在 [方案總管] 視窗中,展開 MainPage.xaml 節點,然後開啟 MainPage.xaml.cs 程式碼後置檔案。

  2. MainPage 類別中,移除 count 變數及 OnCounterClicked 方法。 該類別看起來應該如下所示:

    namespace Phoneword;
    
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }
    }
    
  3. translatedNumber 字串變數和下列 OnTranslate 方法新增至建構函式後方的 MainPage 類別中。 OnTranslate 方法會從 Entry 控制項的 Text 屬性中擷取電話號碼,並將其傳遞至您先前建立 PhonewordTranslator 類別的靜態 ToNumber 方法中。

    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:
            }
        }
    }
    

    注意

    您會在下一個步驟中填入此程式碼所遺漏的 TODO 位元。

  4. OnTranslate 方法中,新增程式碼來變更 [撥號] 按鈕的 Text 屬性,以附加成功轉譯的電話號碼。 可以使用已儲存於 translatedNumber 欄位中的值。 此外,請根據成功的轉譯,啟用和停用按鈕。 例如,若 TranslateNumber 傳回 null,則停用按鈕;若是成功,則啟用按鈕。

    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";
        }
    }
    

建立 CallButton 按鈕的事件方法

  1. OnCall 事件處理方法新增至 MainPage 類別結尾處。 此方法會使用非同步作業,因此請將其標示為 async

    public partial class MainPage : ContentPage
    {
    
        ...
        async void OnCall(object sender, System.EventArgs e)
        {
    
        }
    }
    
  2. OnCall 方法中,使用 Page.DisplayAlert 方法來提示使用者,詢問是否要撥打該電話號碼。

    DisplayAlert 的參數會是標題、訊息及用於 [接受] 和 [取消] 按鈕文字的兩個字串。 它會傳回布林值,以指出是否已按下 [接受] 按鈕以關閉對話方塊。

    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
        }
    }
    

測試應用程式

  1. 在 Visual Studio 工具列中,選取 [Windows 電腦] 設定檔,並開始進行偵錯。

  2. 點選 [轉譯] 按鈕,將預設文字轉換為有效的電話號碼。 [通話] 按鈕上的字幕文字應該會變為 [撥號 1-555-6386284]:

    Phoneword UI 的螢幕擷取畫面。使用者將文字轉譯為有效的電話號碼。

  3. 點選 [通話] 按鈕。 確認會顯示提示,要求您確認此作業。 選取

    螢幕擷取畫面顯示 PhoneWord 使用者介面的撥打電話號碼提示。

  4. 返回 Visual Studio,並停止偵錯。

撥打電話號碼

  1. MainPage.xaml.cs 程式碼後置檔案中,編輯 OnCall 方法,並以後續 try/catch 區塊取代 TODO 註解:

    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");
            }
        }
    }
    

    Microsoft.Maui.Application.Community 命名空間中的 PhoneDialer 類別,會針對 Windows、Android、iOS (和 iPadOS),以及 macOS 平台提供抽象的電話撥號功能 (和其他)。 靜態 Open 方法會嘗試使用電話撥號程式來撥打由參數所提供的號碼。

    下列步驟說明如何更新 Android 應用程式資訊清單,讓 Android 可使用電話撥號程式。 除非您在資訊清單中根據作業系統指定不同的功能,否則 Windows、iOS 和 MacCatalyst 應用程式都會遵循相同的一般性原則。

  2. 在 [方案總管] 視窗中,依序展開 [平台] 資料夾、Android] 資料夾、以滑鼠右鍵按一下 [AndroidManifest.xml 檔案,然後選取 [使用自動編輯器選取器開啟 (XML)]>。 選取 [確定]。

  3. 將下列的 XML 程式碼片段新增至 manifest 節點內現有內容之後。

    <?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>
    
  4. 儲存檔案。

  5. 在 Visual Studio 工具列中,選取 Android Emulators/Pixel 3a - API 30 (或類似項目) 設定檔,然後開始進行偵錯。

  6. 當應用程式出現在模擬器時 (這可能需要幾分鐘),請輸入電話號碼 (或接受預設) 選取 [轉譯],然後選取 [撥號]

  7. 在 [撥打號碼] 警示中,選取 [是]。 確認 Android 電話撥號程式是否顯示了您在應用程式中所提供的號碼。

    Android 手機撥號包含應用程式所提供的號碼。

  8. 返回 Visual Studio,並停止偵錯。

摘要

在本練習中,您已使用頁面和檢視將自訂 UI 新增至應用程式。 您也使用 Android 中所提供的平台專用 API 來新增撥打電話的支援。