[Xamarin初學者04]多頁Xamarin應用程式,Binding Model,Content Page,清單頁裡面的ListView,明細頁,push,pop,async, Navigation.PopAsync,ContentPage.ToolbarItems,ListView.ItemTemplate,如何設定app首頁,OnAppearing

[Xamarin初學者04]多頁Xamarin應用程式,Binding Model,Content Page,清單頁裡面的ListView,明細頁,push,pop,async, Navigation.PopAsync,ContentPage.ToolbarItems,ListView.ItemTemplate,如何設定app首頁,OnAppearing

接續上篇文章[Xamarin初學者03]認識label文字,editor文字編輯區,Grid表格排版,StackLayout整個頁面四周圍的留白

然後於Notes專案底下加入一個Models資料夾,並在資料夾裡面加入一個類別叫做Notes

此類別的內容如下

using System;

namespace Notes.Models
{
    public class Note
    {
        public string Filename { get; set; }
        public string Text { get; set; }
        public DateTime Date { get; set; }
    }
}


接著於Notes專案的根目錄底下加入一個 Content Page(中文叫做內容頁面) 的項目
此項目請取名稱為NoteEntryPage,用web的方式來比喻的話,這是明細頁,查詢清單的每一筆資料的明細頁
當然這也是用xaml做排版的

此明細頁NoteEntryPage.xaml的內容如下
Binding的用處,就是把傳進來的Model的資料,綁定在某個頁面上的element

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Notes.NoteEntryPage"
             Title="Note Entry">
    <StackLayout Margin="20">
	<!-- Binding就是把傳進來的Model類別的Text欄位資料,綁定在這個Editor -->
        <Editor Placeholder="Enter your note"
                Text="{Binding Text}"
                HeightRequest="100" />
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Button Text="Save"
                    Clicked="OnSaveButtonClicked" />
            <Button Grid.Column="1"
                    Text="Delete"
                    Clicked="OnDeleteButtonClicked"/>
        </Grid>
    </StackLayout>
</ContentPage>

並加入NoteEntryPage.xaml的Server端程式碼:NoteEntryPage.xaml.cs
.cs內容如下:
內有註解說明需要注意的地方, 包括語法async, Navigation.PopAsync()

using System;
using System.IO;
using Xamarin.Forms;
using Notes.Models;

namespace Notes
{
    public partial class NoteEntryPage : ContentPage
    {
        public NoteEntryPage()
        {
            InitializeComponent();
        }

        //async的方式執行此function,才不會影響使用者體驗
		async void OnSaveButtonClicked(object sender, EventArgs e)
        {
            var note = (Note)BindingContext;

            if (string.IsNullOrWhiteSpace(note.Filename))
            {
                // Save
                var filename = Path.Combine(App.FolderPath, $"{Path.GetRandomFileName()}.notes.txt");
                File.WriteAllText(filename, note.Text);
            }
            else
            {
                // Update
                File.WriteAllText(note.Filename, note.Text);
            }

            //pop的意思就是回到上一頁
			//在這個專案的情況,將會是回到首頁(即清單頁)
			await Navigation.PopAsync();
        }

        async void OnDeleteButtonClicked(object sender, EventArgs e)
        {
            var note = (Note)BindingContext;

            if (File.Exists(note.Filename))
            {
                File.Delete(note.Filename);
            }

            await Navigation.PopAsync();
        }
    }
}


下一步就是建立我們自己決定的app的首頁(即清單頁),原本預設的首頁MainPage.xaml將會被我們取消掉。

請繼續於Notes專案根目錄底下新增一個 Content Page,名稱取為NotesPage.xaml,這個將會是我們新的首頁(即清單頁)
其內容如下, 並且內有需要注意的語法的註解,包括:ContentPage.ToolbarItems, ListView.ItemTemplate

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Notes.NotesPage"
             Title="Notes">
    <!-- ToolbarItems會在上方顯示海苔條 -->
    <!-- 可以在此海苔條加入任何想要的動作 -->
    <!-- 例如:導向到另一個頁面,或………等等 -->
    <ContentPage.ToolbarItems>
        <ToolbarItem Text="+"
                     Clicked="OnNoteAddedClicked" />
    </ContentPage.ToolbarItems>

    <!-- ListView就類似html的table,曾經用過web form開發網頁的朋友 -->
    <!-- 會發現這個ListView跟當年非常類似 -->
    <!--ItemSelected會觸發點選此筆資料的事件-->    
    <ListView x:Name="listView"
              Margin="20"
              ItemSelected="OnListViewItemSelected">
        <!--ItemTemplate+DataTemplate就是用來顯示每一筆資料-->        
        <ListView.ItemTemplate>
            <DataTemplate>
                <TextCell Text="{Binding Text}"
                          Detail="{Binding Date}" />
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</ContentPage>


再來於NotesPage.xaml.cs加入Server端的行為,讓此清單頁的每一筆資料可以導向到明細頁來顯示明細

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Xamarin.Forms;
using Notes.Models;

namespace Notes
{
    public partial class NotesPage : ContentPage
    {
        public NotesPage()
        {
            InitializeComponent();
        }

		//OnAppearing類似web form應用程式的Page_Load
        protected override void OnAppearing()
        {
            base.OnAppearing();

            var notes = new List<Note>();

            var files = Directory.EnumerateFiles(App.FolderPath, "*.notes.txt");
            foreach (var filename in files)
            {
                notes.Add(new Note
                {
                    Filename = filename,
                    Text = File.ReadAllText(filename),
                    Date = File.GetCreationTime(filename)
                });
            }

            listView.ItemsSource = notes
                .OrderBy(d => d.Date)
                .ToList();
        }

		// 事件請記得都要用async來做非同步執行,才不會影響使用者體驗
        async void OnNoteAddedClicked(object sender, EventArgs e)
        {
			//PushAsync就是進入下一頁
			//這是以資料結構的Stack堆疊的概念來實做的
			//這會傳送一個空白的Note物件到NoteEntryPage
			//用來新增一筆資料
            await Navigation.PushAsync(new NoteEntryPage
            {
                BindingContext = new Note()
            });
        }

        async void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs e)
        {
            if (e.SelectedItem != null)
            {
                await Navigation.PushAsync(new NoteEntryPage
                {
					//把使用者選取的該Note物件傳送到下一頁NoteEntryPage
					//就可以在明細頁顯示明細了
                    BindingContext = e.SelectedItem as Note
                });
            }
        }
    }
}

最後一個步驟請打開App.xaml.cs,這是app一啟動的時候就會執行的程式碼
請加入一個FoldePath變數,這是使用者輸入的資料將會存放的地方
並利用系統變數MainPage來設定新的app首頁,App.xaml.cs明細如下

using System;
using System.IO;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace Notes
{
    public partial class App : Application
    {
        //加入一個變數來儲存路徑
        public static string FolderPath { get; private set; }

        public App()
        {
            InitializeComponent();

            //MainPage = new MainPage();
            //MainPage是內建的系統變數,就是app的首頁            
            FolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData));
            //這行是用來將NotesPage.xaml設定為清單頁(NavigationPage)
            //並且設定此清單頁為首頁
            MainPage = new NavigationPage(new NotesPage());
        }

        protected override void OnStart()
        {
            // Handle when your app starts
        }

        protected override void OnSleep()
        {
            // Handle when your app sleeps
        }

        protected override void OnResume()
        {
            // Handle when your app resumes
        }
    }
}


然後利用Ctrl + F5(或是F5)直接發行到手機測試,首先就利用右上角的 + 符號,新增一筆資料:

並請隨意輸入內容之後,按下 存檔 按鈕

可以看到清單這邊多出一筆內容囉

想要編輯這筆資料的話,在清單畫面點進去該筆資料,並增加任意的內容,最後按下存檔就可以囉

想要刪除這筆資料的話,在清單畫面點進去該筆資料,並按下 刪除 按鈕就可以囉

到此為止的多頁Xamarin應用程式就算是完成了
這篇大概是這樣……
下一篇就會把這邊改用sqlite資料庫來儲存這些資料了
敬請期待

參考資料:
在多頁的 Xamarin. Forms 應用程式中執行流覽
https://docs.microsoft.com/zh-tw/xamarin/get-started/quickstarts/multi-page?pivots=windows