共用方式為


建立 .NET MAUI 應用程式

本教學課程旨在示範如何建立僅使用跨平台程序代碼的 .NET 多平臺應用程式 UI (.NET MAUI) 應用程式。 也就是說,您撰寫的程式代碼不會專屬於 Windows、Android、iOS 或 macOS。 您將建立的應用程式將會是記事應用程式,用戶可以在其中建立、儲存及載入多個筆記。

在本教學課程中,您將瞭解如何:

  • 建立 .NET MAUI Shell 應用程式。
  • 在您選擇的平台上執行您的應用程式。
  • 使用 eXtensible Application Markup Language (XAML) 定義使用者介面,並透過程式代碼與 XAML 元素互動。
  • 建立檢視並將其系結至數據。
  • 使用導覽來往和移出頁面。

您將使用 Visual Studio 2022 建立應用程式,以便輸入附註並將其儲存至裝置記憶體。 最後的應用程式如下所示:

記事應用程式的最終螢幕快照,其中列出附註。 記事應用程式的最後螢幕快照,並新增附註。

建立專案

開始本教學課程之前,您必須先遵循 建置您的第一個應用程式一文。 建立專案時,請使用下列設定:

  • 專案名稱

    這必須設定為 Notes。 如果項目的名稱不同,您從本教學課程複製並貼上的程式代碼可能會導致建置錯誤。

  • 將解決方案和專案放置於同一個目錄

    取消核取此設定。

將 .NET MAUI 專案的名稱設定為 Visual Studio 中的 Notes。

建立專案時,請選擇最新的 .NET 版本。

選取目標裝置

.NET MAUI 應用程式已設計為可在多個作業系統和裝置上執行。 您必須選取您要用來測試和偵錯應用程式的目標。

將 Visual Studio 工具列中的 [偵錯目標] 設定為您想要進行偵錯和測試的裝置。 下列步驟示範將 [ 偵錯目標 ] 設定為 Android:

在 Visual Studio 中選取 .NET MAUI 應用程式的 Android 偵錯目標。

  1. 選取 [ 偵錯目標] 下拉式按鈕。
  2. 選取 [Android 模擬器] 專案。
  3. 選取模擬器裝置。

自訂應用程式殼層

當 Visual Studio 建立 .NET MAUI 專案時,會產生四個重要的程式代碼檔案。 您可以在 Visual Studio 的 [方案總管] 窗格中看到

方案總管 顯示 Visual Studio 中 .NET MAUI 專案的檔案。

這些檔案有助於設定和執行 .NET MAUI 應用程式。 每個檔案都有不同的用途,如下所述:

  • MauiProgram.cs

    這是啟動應用程式的程式代碼檔案。 此檔案中的程式代碼可作為應用程式的跨平臺進入點,其會設定並啟動應用程式。 範本啟動程式代碼會指向 App App.xaml檔案所定義的類別。

  • App.xamlApp.xaml.cs

    為了保持簡單,這兩個檔案都稱為單一檔案。 一般而言,有兩個檔案具有任何 XAML 檔案、.xaml 檔案本身,以及對應程式代碼檔案,其為 方案總管 中的子專案。 .xaml 檔案包含 XAML 標記,而程式代碼檔案則包含使用者建立的程式代碼,以與 XAML 標記互動。

    App.xaml 檔案包含全應用程式 XAML 資源,例如色彩、樣式或範本。 App.xaml.cs檔案通常包含具現化 Shell 應用程式的程式代碼。 在此專案中,它會指向 類別 AppShell

  • AppShell.xamlAppShell.xaml.cs

    此檔案會定義 類別 AppShell ,用來定義應用程式的視覺階層。

  • MainPage.xamlMainPage.xaml.cs

    這是應用程式所顯示的啟動頁面。 MainPage.xaml 檔案會定義頁面的 UI(使用者介面)。 MainPage.xaml.cs包含 XAML 的程式代碼後置,例如按鈕點選事件的程式代碼。

新增 「關於」頁面

您將執行的第一個自訂是將另一個頁面新增至專案。 此頁面是「關於」頁面,代表此應用程式的相關信息,例如作者、版本,以及可能提供詳細信息的連結。

  1. 在 Visual Studio 的 [方案總管] 窗格中,以滑鼠右鍵按一下 [Notes] 專案 >[新增>新項目]

    以滑鼠右鍵按兩下 Visual Studio 中的項目,然後選取[新增專案]。

  2. 在 [ 新增專案 ] 對話框中,選取 視窗左側範本清單中的 .NET MAUI 。 接下來,選取 .NET MAUI ContentPage (XAML) 範本。 將檔案 命名為AboutPage.xaml,然後選取[ 新增]。

    將新的 ContentPage 新增至專案。ContentPage 名為 AboutPage.xaml。

  3. AboutPage.xaml 檔案會開啟新的文件索引標籤,顯示代表頁面 UI 的所有 XAML 標記。 將 XAML 標記取代為下列標記:

    <?xml version="1.0" encoding="utf-8" ?>
    <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="Notes.AboutPage">
        <VerticalStackLayout Spacing="10" Margin="10">
            <HorizontalStackLayout Spacing="10">
                <Image Source="dotnet_bot.png"
                       SemanticProperties.Description="The dot net bot waving hello!"
                       HeightRequest="64" />
                <Label FontSize="22" FontAttributes="Bold" Text="Notes" VerticalOptions="End" />
                <Label FontSize="22" Text="v1.0" VerticalOptions="End" />
            </HorizontalStackLayout>
    
            <Label Text="This app is written in XAML and C# with .NET MAUI." />
            <Button Text="Learn more..." Clicked="LearnMore_Clicked" />
        </VerticalStackLayout>
    </ContentPage>
    
  4. Ctrl+S 或從選單中選取 檔案>儲存 AboutPage.xaml 來儲存檔案。

請細分頁面上所放置 XAML 控制項的主要部分:

  • <ContentPage> 是類別的 AboutPage 根物件。

  • <VerticalStackLayout> 是的唯一子物件 ContentPageContentPage 只能有一個子物件。 此 VerticalStackLayout 類型可以有多個子系。 此佈局控制項會將其子元素依序垂直排列。

  • <HorizontalStackLayout> 操作方式與 <VerticalStackLayout>相同,但其子系會水平排列。

  • <Image> 顯示影像,在此情況下,它會使用 dotnet_bot.png 每個 .NET MAUI 專案隨附的映像。

    這很重要

    新增至項目的檔案實際上是 dotnet_bot.svg。 .NET MAUI 會根據目標裝置,將可調整向量圖形 (SVG) 檔案轉換為可攜式網路圖形 (PNG) 檔案。 因此,將 SVG 檔案新增至 .NET MAUI 應用程式專案時,應該從具有擴展名的 XAML 或 C# .png 加以參考。 SVG 檔案的唯一參考應該在您的項目檔中。

  • <Label> 會控制顯示文字。

  • <Button> 控制項可由引發 事件的使用者 Clicked 按下。 您可以執行程式碼來回應 Clicked 事件。

  • Clicked="LearnMore_Clicked"

    Clicked按鈕的事件會指派給LearnMore_Clicked事件處理程式,該事件處理程式會在程式代碼後置檔案中定義。 您將在下一個步驟中建立此程式碼。

處理 Clicked 事件

下一個步驟是新增按鈕 Clicked 事件的程式碼。

  1. Visual Studio 的 [方案總管] 窗格中,展開 AboutPage.xaml 檔案以顯示其程式代碼後置檔案AboutPage.xaml.cs。 然後,按兩下 AboutPage.xaml.cs 檔案,在程式碼編輯器中開啟它。

    Visual Studio 中 方案總管 視窗的影像,其中紅色方塊醒目提示展開圖示。

  2. 新增下列 LearnMore_Clicked 事件處理程式程式代碼,以將系統瀏覽器開啟至特定 URL:

    private async void LearnMore_Clicked(object sender, EventArgs e)
    {
        // Navigate to the specified URL in the system browser.
        await Launcher.Default.OpenAsync("https://aka.ms/maui");
    }
    

    請注意, async 關鍵詞已新增至方法宣告,以允許在開啟系統瀏覽器時使用 await 關鍵詞。

  3. Ctrl+S 或選取選單中的 [檔案>儲存 AboutPage.xaml.cs] 來儲存檔案。

現在 XAML 和 程式代碼後置 AboutPage 已完成,您必須在應用程式中顯示它。

新增映像資源

某些控制項可以使用影像,以增強使用者與應用程式互動的方式。 在本節中,您將下載兩個您將在應用程式中使用的映像,以及兩個與iOS搭配使用的替代映像。

下載下列影像:

下載映射之後,您可以使用 檔案總管 將它們移至專案的 Resources\Images 資料夾。 此資料夾中的任何檔案都會自動包含在專案中作為 MauiImage 資源。 您也可以使用 Visual Studio 將影像新增至您的專案。 如果您手動移動影像,請略過下列程式。

這很重要

請勿略過下載 iOS 特定圖片,這些圖片是完成本教學課程所需的。

使用 Visual Studio 移動影像

  1. 在 Visual Studio 的 [方案總管] 窗格中,展開 [Resources] 資料夾,其中顯示 [Images] 資料夾。

    小提示

    您可以使用 檔案總管 將影像直接拖放到 [影像] 資料夾頂端的 [方案總管] 窗格中。 這會自動將檔案移至資料夾,並將其包含在專案中。 如果您選擇拖放檔案,請忽略此程序的其餘部分。

  2. 以滑鼠右鍵按兩下 [影像 ],然後選取 [ 新增>現有專案]。

  3. 流覽至包含所下載影像的資料夾。

  4. 將篩選條件更改為檔案類型篩選至 圖片檔案

  5. 按住 Ctrl 鍵並點擊您下載的每個影像,然後按 新增

將四個圖示影像新增至 .NET MAUI 專案。

修改應用程式殼層

如本文開頭所述,類別 AppShell 會定義應用程式的視覺階層,也就是用來建立應用程式 UI 的 XAML 標記。 更新 XAML 以新增 TabBar 控制項:

  1. 按兩下 [方案總管] 窗格中的 AppShell.xaml 檔案,以開啟 XAML 編輯器。 使用以下程式碼替換 XAML 標記:

    <?xml version="1.0" encoding="UTF-8" ?>
    <Shell
        x:Class="Notes.AppShell"
        xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        xmlns:local="clr-namespace:Notes"
        Shell.FlyoutBehavior="Disabled">
    
        <TabBar>
            <ShellContent
                Title="Notes"
                ContentTemplate="{DataTemplate local:MainPage}"
                Icon="{OnPlatform 'icon_notes.png', iOS='icon_notes_ios.png', MacCatalyst='icon_notes_ios.png'}" />
    
            <ShellContent
                Title="About"
                ContentTemplate="{DataTemplate local:AboutPage}"
                Icon="{OnPlatform 'icon_about.png', iOS='icon_about_ios.png', MacCatalyst='icon_about_ios.png'}" />
        </TabBar>
    
    </Shell>
    
  2. Ctrl+S 或選取 [檔案>儲存 AppShell.xaml] 選單來儲存檔案。

讓我們細分 XAML 的主要部分:

  • <Shell> 是 XAML 標記的根物件。
  • <TabBar> 是的內容 Shell
  • 內的<ShellContent>兩個 <TabBar> 物件。 在您取代範本程式代碼之前,有一個指向頁面的單 <ShellContent> 一物件 MainPage

TabBar及其子系不會代表任何使用者介面元素,而是代表應用程式視覺階層的組織。 Shell 會採用這些物件,併產生內容的使用者介面,頂端有代表每個頁面的列。 每個頁面的 ShellContent.Icon 屬性都會使用 OnPlatform 標記延伸。 這個 XAML 標記延伸是用來指定不同平臺的不同值。 在這裡範例中,每個平台預設都會使用 icon_about.png 圖示,但 iOS 和 MacCatalyst 會使用 icon_about_ios.png

每個 <ShellContent> 物件都指向要顯示的頁面。 這是由 ContentTemplate 屬性所設定。

執行應用程式

按 F5 或按下 Visual Studio 頂端的播放按鈕來執行應用程式:

Visual Studio 的 [偵錯目標] 按鈕與文字 Windows 計算機。

您會看到有兩個索引標籤: 附註關於。 按 [ 關於] 索引標籤,應用程式會巡覽至您所建立的 AboutPage 。 按 [ 深入瞭解] 按鈕以開啟網頁瀏覽器。

關於 .NET MAUI 應用程式教學課程的頁面。

關閉應用程式並返回 Visual Studio。 如果您使用 Android 模擬器,請在虛擬裝置中終止應用程式,或按 Visual Studio 頂端的停止按鈕:

Visual Studio 的停止偵錯按鈕。

建立附注的頁面

現在,應用程式包含 MainPageAboutPage,您可以開始建立應用程式的其餘部分。 首先,您將建立一個頁面,讓使用者建立和顯示附註,然後撰寫程式代碼來載入並儲存筆記。

記事頁面會顯示附註,並允許您儲存或刪除它。 首先,將新頁面新增至專案:

  1. 在 Visual Studio 的 [方案總管] 窗格中,以滑鼠右鍵按一下 [Notes] 專案 >[新增>新項目]

  2. 在 [ 新增專案 ] 對話框中,選取 視窗左側範本清單中的 .NET MAUI 。 接下來,選取 .NET MAUI ContentPage (XAML) 範本。 將檔案 命名為 NotePage.xaml,然後選取 [ 新增]。

  3. NotePage.xaml 檔案將會在新索引標籤中開啟,並顯示代表頁面 UI 的所有 XAML 標記。 取代 XAML 程式代碼標記下列標記:

    <?xml version="1.0" encoding="utf-8" ?>
    <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="Notes.NotePage"
                 Title="Note">
        <VerticalStackLayout Spacing="10" Margin="5">
            <Editor x:Name="TextEditor"
                    Placeholder="Enter your note"
                    HeightRequest="100" />
    
            <Grid ColumnDefinitions="*,*" ColumnSpacing="4">
                <Button Text="Save"
                        Clicked="SaveButton_Clicked" />
    
                <Button Grid.Column="1"
                        Text="Delete"
                        Clicked="DeleteButton_Clicked" />
            </Grid>
        </VerticalStackLayout>
    </ContentPage>
    
  4. Ctrl+S 或選取 檔案>儲存 NotePage.xaml 選單來儲存檔案。

請細分頁面上所放置 XAML 控制項的主要部分:

  • <VerticalStackLayout> 垂直排列其子控件,另一個則下方。

  • <Editor> 是多行文本編輯器控件,而且 是 內的 VerticalStackLayout第一個控件。

  • <Grid> 是版面配置控件,而 是 內的 VerticalStackLayout第二個控件。

    此控件會定義要建立儲存格的數據行和數據列。 子控件會放在這些儲存格內。

    根據預設, Grid 控件會包含單一數據列和數據行,並建立單一單元格。 數據行是以寬度定義,而 * 寬度的值會告知數據行盡可能填滿空間。 前一個代碼段定義了兩個數據行,兩個數據行都盡可能多地使用空間,這會平均分散配置空間中的數據行: ColumnDefinitions="*,*"。 數據行大小會以 , 字元分隔。

    由定義的數據行和數據列會 Grid 從 0 開始編製索引。 因此,第一個數據行會是索引 0,第二個數據行是索引 1,依故。

  • <Button> 個控件位於 內 <Grid> 並指派數據行。 如果子控件未定義數據行指派,它會自動指派給第一個數據行。 在此標記中,第一個按鈕是 [儲存] 按鈕,並自動指派給第一個數據行數據行 0。 第二個按鈕是 [刪除] 按鈕,並指派給第二欄第 1 欄。

    請注意,這兩個按鈕已 Clicked 處理 事件。 您將在下一節中新增這些處理程式的程式代碼。

載入並儲存附註

開啟程式代碼後置檔案NotePage.xaml.cs。 您可以透過三種方式開啟 NotePage.xaml 檔案的程式代碼後置:

  • 如果 NotePage.xaml 已開啟,而且是正在編輯的作用中檔,請按 F7
  • 如果 NotePage.xaml 已開啟且正在編輯使用中檔,請在文字編輯器中按兩下滑鼠右鍵,然後選取 [檢視程式代碼]。
  • 使用 方案總管 展開 NotePage.xaml 專案,以顯示NotePage.xaml.cs檔案。 按兩下檔案加以開啟。

當您新增 XAML 檔案時,程式代碼後置會在建構函式中包含單一行,這是對 方法的 InitializeComponent 呼叫:

namespace Notes;

public partial class NotePage : ContentPage
{
    public NotePage()
    {
        InitializeComponent();
    }
}

方法 InitializeComponent 會讀取 XAML 標記,並初始化標記所定義的所有物件。 物件會以其父子式關聯性連接,而且程式代碼中定義的事件處理程式會附加至 XAML 中設定的事件。

既然您已進一步瞭解程式代碼後置檔案,您要將程式代碼新增至 程式代碼後置檔案NotePage.xaml.cs 程式代碼後置檔案,以處理載入和儲存筆記。

  1. 建立附注時,它會以文本檔的形式儲存到裝置。 檔案的名稱是由 _fileName 變數表示。 將下列 string 變數宣告新增至 NotePage 類別:

    public partial class NotePage : ContentPage
    {
        string _fileName = Path.Combine(FileSystem.AppDataDirectory, "notes.txt");
    

    上述程式代碼會建構檔案的路徑,並將它儲存在應用程式的本機數據目錄中。 檔名notes.txt

  2. 在 類別的建構函式中,呼叫 方法之後 InitializeComponent ,從裝置讀取檔案,並將其內容儲存在 TextEditor 控件的 Text 屬性中:

    public NotePage()
    {
        InitializeComponent();
    
        if (File.Exists(_fileName))
            TextEditor.Text = File.ReadAllText(_fileName);
    }
    
  3. 接下來,新增程式代碼以處理 Clicked XAML 中定義的事件:

    private void SaveButton_Clicked(object sender, EventArgs e)
    {
        // Save the file.
        File.WriteAllText(_fileName, TextEditor.Text);
    }
    
    private void DeleteButton_Clicked(object sender, EventArgs e)
    {
        // Delete the file.
        if (File.Exists(_fileName))
            File.Delete(_fileName);
    
        TextEditor.Text = string.Empty;
    }
    

    方法 SaveButton_Clicked 會將控件中的 Editor 文字寫入變數所代表的 _fileName 檔案。

    方法 DeleteButton_Clicked 會先檢查變數所代表的 _fileName 檔案,如果檔案存在,則會將其刪除。 接下來, Editor 會清除控件的文字。

  4. Ctrl+S 或選取功能表 [檔案>儲存 NotePage.xaml.cs] 以儲存檔案。

程序代碼後置檔案的最終程式代碼看起來應該如下所示:

namespace Notes;

public partial class NotePage : ContentPage
{
    string _fileName = Path.Combine(FileSystem.AppDataDirectory, "notes.txt");

    public NotePage()
    {
        InitializeComponent();

        if (File.Exists(_fileName))
            TextEditor.Text = File.ReadAllText(_fileName);
    }

    private void SaveButton_Clicked(object sender, EventArgs e)
    {
        // Save the file.
        File.WriteAllText(_fileName, TextEditor.Text);
    }

    private void DeleteButton_Clicked(object sender, EventArgs e)
    {
        // Delete the file.
        if (File.Exists(_fileName))
            File.Delete(_fileName);

        TextEditor.Text = string.Empty;
    }
}

測試附註

現在記事頁面已完成,您需要一種方式來向用戶呈現它。 開啟 AppShell.xaml 檔案,並將第一個項目ShellContent變更為指向 ,NotePage而不是 MainPage

<?xml version="1.0" encoding="UTF-8" ?>
<Shell
    x:Class="Notes.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:Notes"
    Shell.FlyoutBehavior="Disabled">

    <TabBar>
        <ShellContent
            Title="Notes"
            ContentTemplate="{DataTemplate local:NotePage}"
            Icon="{OnPlatform 'icon_notes.png', iOS='icon_notes_ios.png', MacCatalyst='icon_notes_ios.png'}" />

        <ShellContent
            Title="About"
            ContentTemplate="{DataTemplate local:AboutPage}"
            Icon="{OnPlatform 'icon_about.png', iOS='icon_about_ios.png', MacCatalyst='icon_about_ios.png'}" />
    </TabBar>

</Shell>

儲存盤案並執行應用程式。 請嘗試在輸入方塊中輸入,然後按 [ 儲存] 按鈕。 關閉應用程式,然後重新開啟它。 您輸入的附註應該從裝置的記憶體載入。

注意 .NET MAUI 應用程式中的項目頁面。

將數據系結至UI並瀏覽頁面

本教學課程的這個部分介紹檢視、模型和應用程式內導覽的概念。

在教學課程的先前步驟中,您已將兩個頁面新增至專案: NotePageAboutPage。 頁面代表數據的檢視。 NotePage是顯示「記事數據」的「檢視」,而 AboutPage 是顯示「應用程式資訊數據」的「檢視」。這兩個檢視都有該數據硬式編碼或內嵌的模型,您必須將數據模型與檢視區隔開。

將模型與檢視區隔的優點為何? 它可讓您設計檢視來表示和與模型的任何部分互動,而不必擔心實作模型的實際程序代碼。 這是使用數據系結完成的,本教學課程稍後將會呈現。 不過,現在,讓我們重新建構專案。

分隔檢視和模型

重構現有的程序代碼,以將模型與檢視區隔開。 接下來的幾個步驟會組織程序代碼,讓檢視和模型彼此分開定義。

  1. 從專案中,刪除 MainPage.xamlMainPage.xaml.cs,因為已不再需要。 在 [方案總管] 窗格中,尋找 MainPage.xaml 的項目,並在其上按一下滑鼠右鍵,然後選取 [刪除]

    小提示

    刪除 MainPage.xaml 項目也應該刪除MainPage.xaml.cs專案。 如果未 刪除MainPage.xaml.cs ,請以滑鼠右鍵按兩下它,然後選取 [ 刪除]。

  2. 以滑鼠右鍵按兩下Notes項目,然後選取[新增>資料夾]。 將資料夾命名為 Models

  3. 以滑鼠右鍵按兩下Notes項目,然後選取[新增>資料夾]。 將資料夾命名為 Views

  4. 尋找 NotePage.xaml 專案,並將其拖曳至Views資料夾。 NotePage.xaml.cs應該隨它移動。

    這很重要

    當您移動檔案時,Visual Studio 通常會警告您,移動作業可能需要很長的時間。 如果您看到這個警告,就不應該在這裡發生問題,請按 [確定 ]。

    Visual Studio 也可能詢問您是否要調整已移動檔案的命名空間。 選取 [否 ],因為後續步驟會變更命名空間。

  5. 尋找 AboutPage.xaml 專案,並將其拖曳至Views資料夾。 AboutPage.xaml.cs應該隨它移動。

更新檢視命名空間

現在,檢視已移至 Views 資料夾,您必須更新命名空間以符合。 頁面 XAML 和程式碼後置檔案的命名空間會設定為 Notes。 這必須更新為 Notes.Views

  1. [方案總管] 窗格中,展開 NotePage.xamlAboutPage.xaml,以顯示程式代碼後置檔案:

    具有 Views 資料夾和頁面檢視展開的 Notes 專案。

  2. 按兩下 NotePage.xaml.cs 項目以開啟程式代碼編輯器。 將命名空間變更為 Notes.Views

    namespace Notes.Views;
    
  3. 針對AboutPage.xaml.cs項目重複上述步驟

  4. 按兩下 NotePage.xaml 項目以開啟 XAML 編輯器。 舊命名空間會透過 x:Class 屬性來參考,該屬性會定義哪個類別類型是 XAML 的程式代碼後置。 此專案不只是命名空間,而是具有 型別的命名空間。 將 x:Class 值變更為 Notes.Views.NotePage

    x:Class="Notes.Views.NotePage"
    
  5. 針對 AboutPage.xaml 項目重複上一個步驟,但將 x:Class 值設定為 Notes.Views.AboutPage

修正 Shell 中的命名空間參考

AppShell.xaml 定義兩個索引標籤,一個用於 NotesPage ,另一個用於 AboutPage。 現在,這兩個頁面已移至新的命名空間,XAML 中的類型對應現在無效。 在 [方案總管] 窗格中,按兩下AppShell.xaml專案,在 XAML 編輯器中開啟它。 它看起來應該像下列代碼段:

<?xml version="1.0" encoding="UTF-8" ?>
<Shell
    x:Class="Notes.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:Notes"
    Shell.FlyoutBehavior="Disabled">

    <TabBar>
        <ShellContent
            Title="Notes"
            ContentTemplate="{DataTemplate local:NotePage}"
            Icon="{OnPlatform 'icon_notes.png', iOS='icon_notes_ios.png', MacCatalyst='icon_notes_ios.png'}" />

        <ShellContent
            Title="About"
            ContentTemplate="{DataTemplate local:AboutPage}"
            Icon="{OnPlatform 'icon_about.png', iOS='icon_about_ios.png', MacCatalyst='icon_about_ios.png'}" />
    </TabBar>

</Shell>

.NET 命名空間會透過 XML 命名空間宣告匯入 XAML。 在先前的 XAML 標記中,它是 xmlns:local="clr-namespace:Notes" 根元素中的 屬性: <Shell>。 宣告 XML 命名空間以在相同元件中匯入 .NET 命名空間的格式如下:

xmlns:{XML namespace name}="clr-namespace:{.NET namespace}"

因此,先前的宣告會將的 local XML 命名空間對應至 的 Notes.NET 命名空間。 常見的做法是將名稱 local 對應至專案的根命名空間。

local拿掉 XML 命名空間並新增 XML 命名空間。 這個新的 XML 命名空間會對應至 的 Notes.Views.NET 命名空間,因此請將它命名為 views。 宣告看起來應該像下列屬性: xmlns:views="clr-namespace:Notes.Views"

屬性 local 使用 ShellContent.ContentTemplate XML 命名空間,將它們變更為 views。 您的 XAML 現在看起來應該像下列代碼段:

<?xml version="1.0" encoding="UTF-8" ?>
<Shell
    x:Class="Notes.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:views="clr-namespace:Notes.Views"
    Shell.FlyoutBehavior="Disabled">

    <TabBar>
        <ShellContent
            Title="Notes"
            ContentTemplate="{DataTemplate views:NotePage}"
            Icon="{OnPlatform 'icon_notes.png', iOS='icon_notes_ios.png', MacCatalyst='icon_notes_ios.png'}" />

        <ShellContent
            Title="About"
            ContentTemplate="{DataTemplate views:AboutPage}"
            Icon="{OnPlatform 'icon_about.png', iOS='icon_about_ios.png', MacCatalyst='icon_about_ios.png'}" />
    </TabBar>

</Shell>

您現在應該能夠執行應用程式,而不會發生任何編譯程序錯誤,而且所有專案仍應如先前般運作。

定義模型

模型目前是內嵌在附注和檢視的相關數據。 我們將建立新的類別來表示該數據。 首先,用來代表記事頁數據的模型:

  1. 在 [ 方案總管] 窗格中,以滑鼠右鍵按兩下 Models 資料夾,然後選取[ 新增>類別]。

  2. 將類別 命名為Note.cs ,然後按 [新增]。

  3. 開啟 Note.cs ,並將程式代碼取代為下列代碼段:

    namespace Notes.Models;
    
    internal class Note
    {
        public string Filename { get; set; }
        public string Text { get; set; }
        public DateTime Date { get; set; }
    }
    
  4. 儲存檔案。

接下來,建立關於頁面的模型:

  1. 在 [ 方案總管] 窗格中,以滑鼠右鍵按兩下 Models 資料夾,然後選取[ 新增>類別]。

  2. 將類別 命名為About.cs ,然後按 [新增]。

  3. 開啟 About.cs ,並將程式代碼取代為下列代碼段:

    namespace Notes.Models;
    
    internal class About
    {
        public string Title => AppInfo.Name;
        public string Version => AppInfo.VersionString;
        public string MoreInfoUrl => "https://aka.ms/maui";
        public string Message => "This app is written in XAML and C# with .NET MAUI.";
    }
    
  4. 儲存檔案。

更新關於頁面

關於頁面將是更新最快的頁面,您將能夠執行應用程式,並查看其如何從模型載入數據。

  1. [方案總管] 窗格中,開啟 Views\AboutPage.xaml 檔案。

  2. 將內容取代為下列代碼段:

    <?xml version="1.0" encoding="utf-8" ?>
    <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:models="clr-namespace:Notes.Models"
                 x:Class="Notes.Views.AboutPage"
                 x:DataType="models:About">
        <ContentPage.BindingContext>
            <models:About />
        </ContentPage.BindingContext>
        <VerticalStackLayout Spacing="10" Margin="10">
            <HorizontalStackLayout Spacing="10">
                <Image Source="dotnet_bot.png"
                       SemanticProperties.Description="The dot net bot waving hello!"
                       HeightRequest="64" />
                <Label FontSize="22" FontAttributes="Bold" Text="{Binding Title}" VerticalOptions="End" />
                <Label FontSize="22" Text="{Binding Version}" VerticalOptions="End" />
            </HorizontalStackLayout>
    
            <Label Text="{Binding Message}" />
            <Button Text="Learn more..." Clicked="LearnMore_Clicked" />
        </VerticalStackLayout>
    
    </ContentPage>
    

讓我們看看已變更的行,其反白顯示於上一個代碼段:

  • xmlns:models="clr-namespace:Notes.Models"

    這一行會將 Notes.Models .NET 命名空間對應至 models XML 命名空間。

  • x:DataType="models:About"

    這一行會指示 XAML 編譯程式編譯所有系結表達式以提升運行時間效能,並針對 Notes.Models.About 類型解析系結表達式。

  • BindingContextContentPage 屬性會使用 的 XML 命名空間和 物件,設定為 類別的Note.Models.Aboutmodels:About實例。 這是使用 屬性項目語法 而不是 XML 屬性來設定。

    這很重要

    到目前為止,屬性已使用 XML 屬性來設定。 這適用於簡單的值,例如 Label.FontSize 屬性。 但是,如果屬性值比較複雜,您必須使用 屬性元素語法 來建立物件。 請考慮使用其 FontSize 屬性集建立標籤的下列範例:

    <Label FontSize="22" />
    

    您可以使用屬性元素語法FontSize相同的屬性:

    <Label>
        <Label.FontSize>
            22
        </Label.FontSize>
    </Label>
    
  • <Label> 個控件的 Text 屬性值已從硬式編碼字串變更為系結語法: {Binding PATH}

    {Binding} 語法會在運行時間處理,允許從系結傳回的值是動態的。 的PATH{Binding PATH}一部分是要系結至的屬性路徑。 屬性來自目前控制件的 BindingContext<Label>使用 控件時,BindingContext為 unset。 當控件未設定內容時,內容會繼承自父系,在此情況下,父物件設定內容是根物件: ContentPage

    中的 BindingContext 物件是模型的實例 About 。 其中一個標籤的系結路徑會將 Label.Text 屬性系結至 About.Title 屬性。

關於頁面的最終變更是更新開啟網頁的按鈕按兩下。 URL 在程式代碼後置中已硬式編碼,但URL應該來自屬性中的 BindingContext 模型。

  1. [方案總管] 窗格中,開啟 Views\AboutPage.xaml.cs 檔案。

  2. 以下列程式碼取代 LearnMore_Clicked 方法:

    private async void LearnMore_Clicked(object sender, EventArgs e)
    {
        if (BindingContext is Models.About about)
        {
            // Navigate to the specified URL in the system browser.
            await Launcher.Default.OpenAsync(about.MoreInfoUrl);
        }
    }
    

如果您查看反白顯示的這一行,程式代碼會檢查 是否 BindingContextModels.About 類型,如果為 ,則會將它指派給 about 變數。 語句內的 if 下一行會將瀏覽器開啟至 屬性所提供的 about.MoreInfoUrl URL。

執行應用程式,您應該會看到它執行的方式與之前完全相同。 請嘗試變更模型值的相關信息,並查看瀏覽器開啟的UI和URL如何變更。

更新附註頁面

上一節會將 about 頁面檢視系結至 about 模型,現在您將執行相同的動作,將 note 檢視系結至 note 模型。 不過,在此情況下,不會在 XAML 中建立模型,但會在後續幾個步驟的程式代碼後置中提供。

  1. [方案總管] 窗格中,開啟 Views\NotePage.xaml 檔案。

  2. 將內容取代為下列代碼段:

    <?xml version="1.0" encoding="utf-8" ?>
    <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:models="clr-namespace:Notes.Models"
                 x:Class="Notes.Views.NotePage"
                 Title="Note"
                 x:DataType="models:Note">
        <VerticalStackLayout Spacing="10" Margin="5">
            <Editor x:Name="TextEditor"
                    Placeholder="Enter your note"
                    Text="{Binding Text}"
                    HeightRequest="100" />
    
            <Grid ColumnDefinitions="*,*" ColumnSpacing="4">
                <Button Text="Save"
                        Clicked="SaveButton_Clicked" />
    
                <Button Grid.Column="1"
                        Text="Delete"
                        Clicked="DeleteButton_Clicked" />
            </Grid>
        </VerticalStackLayout>
    </ContentPage>
    

讓我們看看已變更的行,其反白顯示於上一個代碼段:

  • xmlns:models="clr-namespace:Notes.Models"

    這一行會將 Notes.Models .NET 命名空間對應至 models XML 命名空間。

  • x:DataType="models:Note"

    這一行會指示 XAML 編譯程式編譯所有系結表達式以提升運行時間效能,並針對 Notes.Models.Note 類型解析系結表達式。

  • Text="{Binding Text}"

    這一行會藉由新增 <Editor> 屬性,並將 屬性系結至 Text 屬性,來變更 Text 控件。

程序代碼後置的修改比 XAML 複雜。 目前的程式代碼會在建構函式中載入檔案內容,然後將它直接設定為 TextEditor.Text 屬性。 以下是目前程式代碼的外觀:

public NotePage()
{
    InitializeComponent();

    if (File.Exists(_fileName))
        TextEditor.Text = File.ReadAllText(_fileName);
}

建立新的 LoadNote 方法,而不是在建構函式中載入附注。 此方法會執行下列動作:

  • 接受檔名參數。
  • 建立新的記事模型並設定檔名。
  • 如果檔案存在,請將它的內容載入模型。
  • 如果檔案存在,請使用建立檔案的日期更新模型。
  • BindingContext將頁面的 設定為模型。
  1. [方案總管] 窗格中,開啟 Views\NotePage.xaml.cs 檔案。

  2. 將下列方法新增至 班級:

    private void LoadNote(string fileName)
    {
        Models.Note noteModel = new Models.Note();
        noteModel.Filename = fileName;
    
        if (File.Exists(fileName))
        {
            noteModel.Date = File.GetCreationTime(fileName);
            noteModel.Text = File.ReadAllText(fileName);
        }
    
        BindingContext = noteModel;
    }
    
  3. 更新類別建構函式以呼叫 LoadNote。 附註的檔名應該是隨機產生的名稱,以在應用程式的本機數據目錄中建立。

    public NotePage()
    {
        InitializeComponent();
    
        string appDataPath = FileSystem.AppDataDirectory;
        string randomFileName = $"{Path.GetRandomFileName()}.notes.txt";
    
        LoadNote(Path.Combine(appDataPath, randomFileName));
    }
    

新增列出所有附注的檢視和模型

本教學課程的這個部分會新增應用程式的最後一個部分,此檢視會顯示先前建立的所有筆記。

多個附註和流覽

目前記 事檢視會顯示單一附註 。 若要顯示多個筆記,請建立新的檢視和模型: AllNotes

  1. 在 [方案總管] 窗格中,以滑鼠右鍵按兩下Views資料夾,然後選取[新增>
  2. 在 [ 新增專案 ] 對話框中,選取 視窗左側範本清單中的 .NET MAUI 。 接下來,選取 .NET MAUI ContentPage (XAML) 範本。 將檔案 命名為 AllNotesPage.xaml,然後選取 [ 新增]。
  3. [方案總管] 窗格中,以滑鼠右鍵按兩下Models資料夾,然後選取[新增>
  4. 將類別 命名為AllNotes.cs ,然後按 [新增]。

撰寫 AllNotes 模型的程式代碼

新的模型將代表顯示多個筆記所需的數據。 此數據會是代表附註集合的屬性。 集合將會是 ObservableCollection 特製化集合的 。 當列出多個專案的控件,例如 ListView, 系結至 ObservableCollection時,兩者會一起運作,以自動讓專案清單與集合保持同步。 如果清單新增專案,則會更新集合。 如果集合加入專案,控件就會自動更新為新的專案。

  1. [方案總管] 窗格中,開啟 Models\AllNotes.cs 檔案。

  2. 使用下列片段取代程式碼:

    using System.Collections.ObjectModel;
    
    namespace Notes.Models;
    
    internal class AllNotes
    {
        public ObservableCollection<Note> Notes { get; set; } = new ObservableCollection<Note>();
    
        public AllNotes() =>
            LoadNotes();
    
        public void LoadNotes()
        {
            Notes.Clear();
    
            // Get the folder where the notes are stored.
            string appDataPath = FileSystem.AppDataDirectory;
    
            // Use Linq extensions to load the *.notes.txt files.
            IEnumerable<Note> notes = Directory
    
                // Select the file names from the directory
                .EnumerateFiles(appDataPath, "*.notes.txt")
    
                // Each file name is used to create a new Note
                .Select(filename => new Note()
                {
                    Filename = filename,
                    Text = File.ReadAllText(filename),
                    Date = File.GetLastWriteTime(filename)
                })
    
                // With the final collection of notes, order them by date
                .OrderBy(note => note.Date);
    
            // Add each note into the ObservableCollection
            foreach (Note note in notes)
                Notes.Add(note);
        }
    }
    

上述程式代碼會宣告名為 Notes的集合,並使用 LoadNotes 方法從裝置載入筆記。 此方法會使用 LINQ 擴充功能,將數據載入、轉換和排序至 Notes 集合。

設計 AllNotes 頁面

接下來,檢視必須設計為支援 AllNotes 模型。

  1. [方案總管] 窗格中,開啟 Views\AllNotesPage.xaml 檔案。

  2. 以下列標記取代程式代碼:

    <?xml version="1.0" encoding="utf-8" ?>
    <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:models="clr-namespace:Notes.Models"
                 x:Class="Notes.Views.AllNotesPage"
                 Title="Your Notes"
                 x:DataType="models:AllNotes">
        <!-- Add an item to the toolbar -->
        <ContentPage.ToolbarItems>
            <ToolbarItem Text="Add" Clicked="Add_Clicked" IconImageSource="{FontImage Glyph='+', Color=Black, Size=22}" />
        </ContentPage.ToolbarItems>
    
        <!-- Display notes in a list -->
        <CollectionView x:Name="notesCollection"
                            ItemsSource="{Binding Notes}"
                            Margin="20"
                            SelectionMode="Single"
                            SelectionChanged="notesCollection_SelectionChanged">
    
            <!-- Designate how the collection of items are laid out -->
            <CollectionView.ItemsLayout>
                <LinearItemsLayout Orientation="Vertical" ItemSpacing="10" />
            </CollectionView.ItemsLayout>
    
            <!-- Define the appearance of each item in the list -->
            <CollectionView.ItemTemplate>
                <DataTemplate x:DataType="models:Note">
                    <StackLayout>
                        <Label Text="{Binding Text}" FontSize="22"/>
                        <Label Text="{Binding Date}" FontSize="14" TextColor="Silver"/>
                    </StackLayout>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </ContentPage>
    

先前的 XAML 引進了一些新概念:

  • 屬性 ContentPage.ToolbarItems 包含 ToolbarItem。 這個處定義的按鈕通常會顯示在應用程式頂端,並沿著頁面標題顯示。 不過,視平臺而定,它可能處於不同的位置。 按下其中一個按鈕時, Clicked 就會引發 事件,就像一般按鈕一樣。

    屬性會 ToolbarItem.IconImageSource 設定要顯示在按鈕上的圖示。 圖示可以是專案所定義的任何影像資源,但在此範例中會 FontImage 使用 。 FontImage可以使用字型的單一圖像做為影像。

  • 控件 CollectionView 會顯示專案的集合,在此情況下,會系結至模型的 Notes 屬性。 集合檢視會透過 CollectionView.ItemsLayoutCollectionView.ItemTemplate 屬性設定每個專案的方式。

    針對集合中的每個專案,會產生 CollectionView.ItemTemplate 宣告的 XAML。 BindingContext該 XAML 的 會變成集合專案本身,在此案例中,每個個別的附註。 附註的範本會使用兩個標籤,這些標籤系結至附註的 TextDate 屬性。

  • CollectionView 處理 SelectionChanged 事件,此事件會在選取集合檢視中的項目時引發。

檢視的程式代碼後置必須寫入以載入附注並處理事件。

  1. [方案總管] 窗格中,開啟 Views/AllNotesPage.xaml.cs 檔案。

  2. 使用下列片段取代程式碼:

    namespace Notes.Views;
    
    public partial class AllNotesPage : ContentPage
    {
        public AllNotesPage()
        {
            InitializeComponent();
    
            BindingContext = new Models.AllNotes();
        }
    
        protected override void OnAppearing()
        {
            ((Models.AllNotes)BindingContext).LoadNotes();
        }
    
        private async void Add_Clicked(object sender, EventArgs e)
        {
            await Shell.Current.GoToAsync(nameof(NotePage));
        }
    
        private async void notesCollection_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (e.CurrentSelection.Count != 0)
            {
                // Get the note model
                var note = (Models.Note)e.CurrentSelection[0];
    
                // Should navigate to "NotePage?ItemId=path\on\device\XYZ.notes.txt"
                await Shell.Current.GoToAsync($"{nameof(NotePage)}?{nameof(NotePage.ItemId)}={note.Filename}");
    
                // Unselect the UI
                notesCollection.SelectedItem = null;
            }
        }
    }
    

此程式代碼會使用 建構函式將頁面的 設定 BindingContext 為模型。

方法 OnAppearing 會從基類覆寫。 每當顯示頁面時,就會自動呼叫這個方法,例如巡覽至頁面時。 這裡的程式代碼會告訴模型載入附註。 CollectionView由於 AllNotes 檢視中的 系結至 AllNotes 模型的Notes 屬性,也就是 ObservableCollection,每當載入筆記時,CollectionView就會自動更新 。

處理程序 Add_Clicked 引進了另一個新概念導覽。 由於應用程式使用 .NET MAUI Shell,因此您可以藉由呼叫 Shell.Current.GoToAsync 方法來巡覽至頁面。 請注意,處理程式是以 關鍵詞宣告 async ,這允許在巡覽時使用 await 關鍵詞。 此處理程式會巡覽至 NotePage

上一個代碼段中的最後一段程式代碼是 notesCollection_SelectionChanged 處理程式。 這個方法會採用目前選取的專案模型 Note ,並使用其資訊來巡覽至 NotePageGoToAsync 會使用 URI 字串進行流覽。 在此情況下,會建構使用查詢字串參數在目的地頁面上設定屬性的字串。 表示 URI 的插補字串最終看起來類似下列字串:

NotePage?ItemId=path\on\device\XYZ.notes.txt

參數 ItemId= 會設定為儲存附註之裝置上的檔名。

Visual Studio 可能表示 NotePage.ItemId 屬性不存在,而這是真的。 下一個步驟是修改 Note 檢視 ,以根據您將建立的參數 ItemId 載入模型。

查詢字串參數

檢視Note必須支援查詢字串參數 ItemId。 立即建立:

  1. [方案總管] 窗格中,開啟 Views/NotePage.xaml.cs 檔案。

  2. QueryProperty 屬性新增至 class 關鍵詞,並提供查詢字串屬性的名稱,以及它對應至的類別屬性, ItemId 以及 ItemId 分別對應至 的類別屬性:

    [QueryProperty(nameof(ItemId), nameof(ItemId))]
    public partial class NotePage : ContentPage
    
  3. 新增名為 string的新ItemId屬性。 這個屬性會呼叫 LoadNote 方法,並傳遞 屬性的值,這反過來應該是附註的檔名:

    public string ItemId
    {
        set { LoadNote(value); }
    }
    
  4. SaveButton_Clicked以下欄程序代碼取代和 DeleteButton_Clicked 處理程式:

    private async void SaveButton_Clicked(object sender, EventArgs e)
    {
        if (BindingContext is Models.Note note)
            File.WriteAllText(note.Filename, TextEditor.Text);
    
        await Shell.Current.GoToAsync("..");
    }
    
    private async void DeleteButton_Clicked(object sender, EventArgs e)
    {
        if (BindingContext is Models.Note note)
        {
            // Delete the file.
            if (File.Exists(note.Filename))
                File.Delete(note.Filename);
        }
    
        await Shell.Current.GoToAsync("..");
    }
    

    按鍵現在是 async。 按下之後,頁面會使用的 ..URI 來巡覽回上一頁。

  5. 從程式 _fileName 代碼頂端刪除變數,因為它不再由類別使用。

修改應用程式的視覺化樹狀結構

AppShell仍在載入單一記事頁面,而是需要載入AllPages檢視開啟 AppShell.xaml 檔案,並將第一個項目ShellContent變更為指向 ,AllNotesPage而不是 NotePage

<?xml version="1.0" encoding="UTF-8" ?>
<Shell
    x:Class="Notes.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:views="clr-namespace:Notes.Views"
    Shell.FlyoutBehavior="Disabled">

    <TabBar>
        <ShellContent
            Title="Notes"
            ContentTemplate="{DataTemplate views:AllNotesPage}"
            Icon="{OnPlatform 'icon_notes.png', iOS='icon_notes_ios.png', MacCatalyst='icon_notes_ios.png'}" />

        <ShellContent
            Title="About"
            ContentTemplate="{DataTemplate views:AboutPage}"
            Icon="{OnPlatform 'icon_about.png', iOS='icon_about_ios.png', MacCatalyst='icon_about_ios.png'}" />
    </TabBar>

</Shell>

如果您現在執行應用程式,如果您按下 [新增 ] 按鈕,就會發現它當機,抱怨它無法瀏覽至 NotesPage。 每個可以從另一個頁面巡覽至的頁面,都必須嚮導覽系統註冊。 AllNotesPageAboutPage 頁面會在 中TabBar宣告,自動嚮導覽系統註冊。

NotesPage精靈覽系統註冊 :

  1. [方案總管] 窗格中,開啟AppShell.xaml.cs檔案。

  2. 將一行新增至註冊導覽路由的建構函式:

    namespace Notes;
    
    public partial class AppShell : Shell
    {
        public AppShell()
        {
            InitializeComponent();
    
            Routing.RegisterRoute(nameof(Views.NotePage), typeof(Views.NotePage));
        }
    }
    

Routing.RegisterRoute 方法採用兩個參數:

  • 第一個參數是您想要註冊之 URI 的字串名稱,在此情況下,解析的名稱為 "NotePage"
  • 第二個參數是巡覽至 時 "NotePage" 要載入的頁面類型。

現在您可以執行您的應用程式。 請嘗試新增筆記、在筆記之間來回巡覽,以及刪除筆記。

探索程序代碼。 探索本教學課程的程序代碼。 如果您要下載已完成項目的復本來比較您的程式代碼,請下載 此專案

您已完成建立 .NET MAUI 應用程式教學課程!

後續步驟

在下一個教學中,您將學會如何在您的專案中實現模型-視圖-視圖模型(MVVM)模式。

下列連結提供您在本教學課程中學到之一些概念的詳細資訊: