XAML in Xamarin.Forms 基礎篇 電子書

XAML in Xamarin.Forms 基礎篇 電子書
XAML in Xamarin.Forms 基礎篇 電子書

Xamarin.Forms 快速入門 電子書

Xamarin.Forms 快速入門 電子書
Xamarin.Forms 快速入門 電子書

2016/09/12

Xamarin.Forms 使用者自訂對話窗與PopUp應用 頁面

使用者自訂對話窗與PopUp應用 頁面

目的

當在進行 Xamarin.Forms 專案開發的時候,除了 Xamarin.Forms 基本提供的 DisplayAlert 與DisplayActionSheet,而在 Prism 開發框架之下,也可以使用建構式注入 IPageDialogService 介面,透過其注入的執行個體,使用 DisplayAlertAsync 與 DisplayActionSheetAsync,來與使用者進行互動。很多時候,您也希望能夠告知應用程式操作的使用者,現在應用程式正在忙碌執行中,並且顯示出相關訊息,讓使用者知道現在處理請況;或者,需要能夠顯示一個客製的對話窗,讓使用者輸入或者填寫相關訊息,而不需要做頁面切換。
在這篇文章中,將會說明如何客製一個使用者對話窗,並且產生一個頁面遮罩,讓這個對話窗顯示在原來頁面之上。
對話窗與動作選項

學習重點

在這個練習專案中,將會讓您學會底下技能與方法的使用:
  • 使用 ContentView 產生許多使用者控制項 (User Control),可以反覆使用的控制項
  • 如何在相關頁面之中,引用這些新建立的使用者控制項
  • 使用檢視模型 (ViewModel) 來控制使用者控制項顯示與否和進行資料繫結
  • 如何處理與回應使用者控制項中的相關事件或者 ICommand
  • 使用顏色來表示螢幕遮罩的方法
  • 讀取使用者控制項所輸入或者回應的資料和訊息
  • 在 XAML 內,使用手勢操作(GestureRecognizers)判斷使用者點選使用者控制項,以便中止顯示該控制項

專案原始碼

專案使用到的圖片

實作方法

建立專案

  1. 在 Visual Studio 2015,點選功能表 檔案 > 新增 > 專案
  2. 在 新增專案 對話窗內,點選 範本 > Visual C# > Prism > Prism Unity App (Forms)
  3. 在底下名稱欄位中,輸入 CustomDiag 最後,點選 確定 按鈕。
  4. 當出現 Prism for Xamarin.Forms - Project Wizard 對話窗,請勾選 AndroidiOSUWP 這三個選項,表示您想要產生使用 Prism 框架的這三種原生 Xamarin.Forms 專案,最後點選 Create 按鈕。
當專案建立到一半,若您的開發環境還沒有建置與設定完成 Mac 電腦與 Xamarin Studio for Mac 系統,此時會看到 Xamarin Mac Agent Instructions 對話窗出現,這個對話窗是要提醒您進行與 Mac 電腦連線設定,這是因為,您無法在 Windows 作業系統進行 iOS 相關應用程式的建立與設計工作,而是需要透過 Mac 電腦安裝的 XCode 來協助您完成這些 iOS 應用程式的建立工作。不過,這不影響您繼續開發 Xamarin.Forms 的應用程式,只不過此時,您無法編譯與執行 iOS 的應用程式。
  1. 接著會看到 新的通用Windows專案 對話視窗,此時,您只需要按下 確定 按鈕即可,此時,專案精靈會繼續完成相關平台的專案建立工作。
  2. 最後,整個新的 Xamarin.Forms 專案就建立完成了。
若您無法看到 Prism 項目,用來建立 Prism 類型專案,那可能是您的 Visual Studio 2015 內沒有安裝Prism Template Pack 擴充功能,請參考 附件 : 使用 Visual Studio 2015 增加 Prism 專案樣版
  1. 滑鼠右擊 CustomDiag.Droid,選擇 設定為起始專案
  2. 展開 CustomDiag.Droid > Properties,滑鼠雙擊 Properties 這個節點
  3. 在標籤頁次 Application,選擇項目 Minimum Android to target的下拉選單,選擇值為 Android 4.4 (API Level 19 - Kit Kat) 這個選項,接著按下 Ctrl + S 組合案件,儲存此次修改設定。
  4. 滑鼠右擊 CustomDiag.Droid,選擇 建置 進行專案編譯

開發前準備工作

建立資料夾

  1. 請在核心PCL 專案內,建立一個 UserControls 資料夾

複製專案使用的圖片檔案

專案開發

建立 CustDialogUserControl 使用者控制項 (User COntrol)

  1. 滑鼠右擊核心PCL專案的 UserControls 資料夾,選擇 加入 > 新增項目
  2. 在對話窗點選 Visual C# > Cross-Platform > Forms Xaml Page
  3. 在名稱欄位輸入 CustDialogUserControl,接著點選 新增 按鈕
  4. 將底下 XAML 標記宣告複製到剛剛建立的檔案內

CustDialogUserControl.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CustomDiag.UserControls.CustDialogUserControl">

  <!--<ScrollView    
    Orientation="Vertical"
    VerticalOptions="Fill" HorizontalOptions="Fill"
      >
  </ScrollView>-->
  <Grid
    HorizontalOptions="Fill" VerticalOptions="Fill"
    >
    <BoxView
      BackgroundColor="#BB000000"
      />
    <BoxView
      BackgroundColor="#FFFFFFFF"
      Margin="20,70"
      />
    <StackLayout
      Margin="40,80"
      HorizontalOptions="Fill" VerticalOptions="Start"
      >
      <Label
        Text="{Binding 客製化使用者對話窗ViewModel.對話窗主題}"
        TextColor="#000000"
        FontSize="30"
        HorizontalOptions="Center"
        Margin="0,40,0,20"
        />
      <Label
        Text="{Binding 客製化使用者對話窗ViewModel.對話窗訊息}"
        TextColor="#000000"
        Margin="20,20,20,30"
        FontSize="18"
        HorizontalTextAlignment="Center"
        HorizontalOptions="Center"
        />
      <Label Text="帳號" />
      <Entry
        HorizontalOptions="Fill"
        Text="{Binding 客製化使用者對話窗ViewModel.對話窗使用者帳號}"
        />
      <Label Text="密碼" />
      <Entry
        HorizontalOptions="Fill"
        Text="{Binding 客製化使用者對話窗ViewModel.對話窗使使用者密碼}"
        IsPassword="True"
        />
      <StackLayout
        Orientation="Horizontal"
        HorizontalOptions="Center"
        >
        <Button
          Text="確定"
          Command="{Binding 客製化對話窗確定Command}"
        />
        <Button
          Text="取消"
          Command="{Binding 客製化對話窗取消Command}"
        />
      </StackLayout>
    </StackLayout>
  </Grid>

</ContentView>
  1. 在核心PCL專案的 UserControls 資料夾,開啟 CustDialogUserControl.xaml.cs 檔案
  2. 將底下 C# 複製到剛剛開啟的檔案內

CustDialogUserControl.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;

namespace CustomDiag.UserControls
{
    public partial class CustDialogUserControl : ContentView
    {
        public CustDialogUserControl()
        {
            InitializeComponent();
        }
    }
}

建立 ProcessingUserControl 使用者控制項 (User COntrol)

  1. 滑鼠右擊核心PCL專案的 UserControls 資料夾,選擇 加入 > 新增項目
  2. 在對話窗點選 Visual C# > Cross-Platform > Forms Xaml Page
  3. 在名稱欄位輸入 ProcessingUserControl,接著點選 新增 按鈕
  4. 將底下 XAML 標記宣告複製到剛剛建立的檔案內

ProcessingUserControl.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CustomDiag.UserControls.ProcessingUserControl">

  <Grid
    HorizontalOptions="Fill" VerticalOptions="Fill"
    >
    <Grid.RowDefinitions>
      <RowDefinition Height="*" />
      <RowDefinition Height="150" />
    </Grid.RowDefinitions>
    <BoxView
      Grid.Row="0" Grid.RowSpan="2"
      BackgroundColor="#BB000000"
      >
      <BoxView.GestureRecognizers>
        <TapGestureRecognizer
                Command="{Binding 點選遮罩Command}"
                NumberOfTapsRequired="1" />
      </BoxView.GestureRecognizers>
    </BoxView>
    <StackLayout
      Grid.Row="0"
      HorizontalOptions="Center" VerticalOptions="Center"
      Margin="20,0"
      >
      <Label
        Text="{Binding 處理中ViewModel.處理中訊息}"
        TextColor="#FFFFFF"
        FontSize="30"
        HorizontalOptions="Center"
        />
      <Label 
        Text="{Binding 處理中ViewModel.處理中狀態文字}"
        TextColor="#FFFFFF"
        Margin="0,30,0,0"
        FontSize="20"
        HorizontalOptions="Center"
        />
    </StackLayout>
    <ActivityIndicator
     Grid.Row="1"
     Color="#53ff1a"
     WidthRequest="50" HeightRequest="50"
     HorizontalOptions="Center" VerticalOptions="Center"
     IsRunning="{Binding 處理中ViewModel.忙碌中控制項使用中}"
     />
  </Grid>
</ContentView>
  1. 在核心PCL專案的 UserControls 資料夾,開啟 ProcessingUserControl.xaml.cs 檔案
  2. 將底下 C# 複製到剛剛開啟的檔案內

ProcessingUserControl.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;

namespace CustomDiag.UserControls
{
    public partial class ProcessingUserControl : ContentView
    {
        public ProcessingUserControl()
        {
            InitializeComponent();
        }
    }
}

修改 MainPage 檢視 (View)

  1. 在核心PCL專案的 Views 資料夾,滑鼠雙擊 MainPage.xaml
  2. 將底下 XAML 複製到剛剛開啟的檔案內

MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             xmlns:UserControls="clr-namespace:CustomDiag.UserControls"
             x:Class="CustomDiag.Views.MainPage"
             BackgroundColor="#ffaa80"
             Title="MainPage">
  <Grid>
    <StackLayout
      Spacing="30"
      HorizontalOptions="Center" VerticalOptions="Center">
      <Button Text="客製化對話窗"
              Command="{Binding 客製化對話窗Command}"
               />
      <Label Text="{Binding 使用者輸入內容}"/>
      <Button Text="處理中遮罩" 
              Command="{Binding 處理中遮罩Command}"/>
    </StackLayout>
    <UserControls:ProcessingUserControl 
      IsVisible="{Binding 處理中ViewModel.顯示處理中遮罩}"
      />
    <UserControls:CustDialogUserControl 
      IsVisible="{Binding 客製化使用者對話窗ViewModel.顯示客製化使用者對話窗}"
      />
  </Grid>
</ContentPage>

建立 CustDialogUserControlViewModel 檢視模型 (ViewModel)

  1. 滑鼠右擊核心PCL專案的 ViewModels 資料夾,選擇 加入 > 新增項目
  2. 在對話窗點選 Visual C# > Prism > Prism ViewModel
  3. 在名稱欄位輸入 CustDialogUserControlViewModel,接著點選 新增 按鈕
  4. 將底下 C# 程式碼複製到剛剛建立的檔案內

CustDialogUserControlViewModel.cs

using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;

namespace CustomDiag.ViewModels
{
    public class CustDialogUserControlViewModel : BindableBase
    {
        #region ViewModel
        #region 顯示客製化使用者對話窗
        private bool _顯示客製化使用者對話窗 = false;

        public bool 顯示客製化使用者對話窗
        {
            get { return _顯示客製化使用者對話窗; }
            set { SetProperty(ref _顯示客製化使用者對話窗, value); }
        }
        #endregion

        #region 對話窗主題
        private string _對話窗主題 = "";

        public string 對話窗主題
        {
            get { return _對話窗主題; }
            set { SetProperty(ref _對話窗主題, value); }
        }
        #endregion

        #region 對話窗訊息
        private string _對話窗訊息 = "";

        public string 對話窗訊息
        {
            get { return _對話窗訊息; }
            set { SetProperty(ref _對話窗訊息, value); }
        }
        #endregion

        #region 對話窗使用者帳號
        private string _對話窗使用者帳號 = "";

        public string 對話窗使用者帳號
        {
            get { return _對話窗使用者帳號; }
            set { SetProperty(ref _對話窗使用者帳號, value); }
        }
        #endregion

        #region 對話窗使使用者密碼
        private string _對話窗使使用者密碼 = "";

        public string 對話窗使使用者密碼
        {
            get { return _對話窗使使用者密碼; }
            set { SetProperty(ref _對話窗使使用者密碼, value); }
        }
        #endregion

        #endregion

        public CustDialogUserControlViewModel()
        {

        }

        public void 顯示客製化使用者對話窗控制項(string p對話窗主題, string p對話窗訊息)
        {
            對話窗主題 = p對話窗主題;
            對話窗訊息 = p對話窗訊息;
            對話窗使用者帳號 = "";
            對話窗使使用者密碼 = "";
            顯示客製化使用者對話窗 = true;
        }

        public void 關閉客製化使用者對話窗控制項()
        {
            顯示客製化使用者對話窗 = false;
        }

    }
}

建立 ProcessingUserControlViewModel 檢視模型 (ViewModel)

  1. 滑鼠右擊核心PCL專案的 ViewModels 資料夾,選擇 加入 > 新增項目
  2. 在對話窗點選 Visual C# > Prism > Prism ViewModel
  3. 在名稱欄位輸入 ProcessingUserControlViewModel,接著點選 新增 按鈕
  4. 將底下 C# 程式碼複製到剛剛建立的檔案內

ProcessingUserControlViewModel.cs

using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;

namespace CustomDiag.ViewModels
{
    public class ProcessingUserControlViewModel : BindableBase
    {
        #region ViewModel
        #region 顯示處理中遮罩
        private bool _顯示處理中遮罩 = false;

        public bool 顯示處理中遮罩
        {
            get { return _顯示處理中遮罩; }
            set { SetProperty(ref _顯示處理中遮罩, value); }
        }
        #endregion

        #region 忙碌中控制項使用中
        private bool _忙碌中控制項使用中 = true;

        public bool 忙碌中控制項使用中
        {
            get { return _忙碌中控制項使用中; }
            set { SetProperty(ref _忙碌中控制項使用中, value); }
        }
        #endregion

        #region 處理中訊息
        private string _處理中訊息 = "";

        public string 處理中訊息
        {
            get { return _處理中訊息; }
            set { SetProperty(ref _處理中訊息, value); }
        }
        #endregion

        #region 處理中狀態文字
        private string _處理中狀態文字 = "";

        public string 處理中狀態文字
        {
            get { return _處理中狀態文字; }
            set { SetProperty(ref _處理中狀態文字, value); }
        }
        #endregion

        #endregion

        public ProcessingUserControlViewModel()
        {

        }

        public void 顯示忙碌中使用者控制項(string p處理中訊息, string p處理中狀態文字)
        {
            處理中訊息 = p處理中訊息;
            處理中狀態文字 = p處理中狀態文字;
            顯示處理中遮罩 = true;
            忙碌中控制項使用中 = true;
        }

        public void 關閉忙碌中使用者控制項()
        {
            處理中訊息 = "";
            處理中狀態文字 = "";
            顯示處理中遮罩 = false;
            忙碌中控制項使用中 = false;
        }

    }
}

修改 MainPageViewModel 檢視模型 (ViewModel)

  1. 在核心PCL專案的 Views 資料夾,滑鼠雙擊 MainPageViewModel.cs
  2. 將底下 XAML 複製到剛剛開啟的檔案內

MainPageViewModel.cs

using Prism.Commands;
using Prism.Mvvm;
using Prism.Navigation;
using Prism.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace CustomDiag.ViewModels
{
    public class MainPageViewModel : BindableBase, INavigationAware
    {
        #region DI
        INavigationService _navigationService;
        IPageDialogService _dialogService;
        #endregion

        #region ICommand
        public DelegateCommand 客製化對話窗Command { get; set; }
        public DelegateCommand 處理中遮罩Command { get; set; }
        public DelegateCommand 點選遮罩Command { get; set; }
        public DelegateCommand 客製化對話窗確定Command { get; set; }
        public DelegateCommand 客製化對話窗取消Command { get; set; }
        #endregion

        #region ViewModel
        #region 顯示客製化對話窗
        private bool _顯示客製化對話窗 = false;

        public bool 顯示客製化對話窗
        {
            get { return _顯示客製化對話窗; }
            set { SetProperty(ref _顯示客製化對話窗, value); }
        }
        #endregion

        #region 對話窗主題
        private string _對話窗主題 = "";

        public string 對話窗主題
        {
            get { return _對話窗主題; }
            set { SetProperty(ref _對話窗主題, value); }
        }
        #endregion

        #region 對話窗內容
        private string _對話窗內容 = "";

        public string 對話窗內容
        {
            get { return _對話窗內容; }
            set { SetProperty(ref _對話窗內容, value); }
        }
        #endregion

        #region 使用者輸入內容
        private string _使用者輸入內容 = "";

        public string 使用者輸入內容
        {
            get { return _使用者輸入內容; }
            set { SetProperty(ref _使用者輸入內容, value); }
        }
        #endregion
        public ProcessingUserControlViewModel 處理中ViewModel { get; set; } = new ProcessingUserControlViewModel();
        public CustDialogUserControlViewModel 客製化使用者對話窗ViewModel { get; set; } = new CustDialogUserControlViewModel();
        #endregion

        public MainPageViewModel(INavigationService navigationService, IPageDialogService dialogService)
        {
            _navigationService = navigationService;
            _dialogService = dialogService;

            客製化對話窗Command = new DelegateCommand(客製化對話窗);
            處理中遮罩Command = new DelegateCommand(處理中遮罩);
            點選遮罩Command = new DelegateCommand(點選遮罩);
            客製化對話窗確定Command = new DelegateCommand(客製化對話窗確定);
            客製化對話窗取消Command = new DelegateCommand(客製化對話窗取消);
        }

        private void 客製化對話窗取消()
        {
            使用者輸入內容 = "";
            客製化使用者對話窗ViewModel.關閉客製化使用者對話窗控制項();
        }

        private async void 客製化對話窗確定()
        {
            if (string.IsNullOrEmpty(客製化使用者對話窗ViewModel.對話窗使用者帳號) || 客製化使用者對話窗ViewModel.對話窗使用者帳號.Length < 6)
            {
                await _dialogService.DisplayAlertAsync("警告", "帳號不可為空值或者小於6個字元", "確定");
            }
            else if (string.IsNullOrEmpty(客製化使用者對話窗ViewModel.對話窗使使用者密碼) || 客製化使用者對話窗ViewModel.對話窗使使用者密碼.Length < 8)
            {
                await _dialogService.DisplayAlertAsync("警告", "密碼不可為空值或者小於8個字元", "確定");
            }
            else
            {
                使用者輸入內容 = $"帳號:{客製化使用者對話窗ViewModel.對話窗使用者帳號} / 密碼: {客製化使用者對話窗ViewModel.對話窗使使用者密碼}";
                客製化使用者對話窗ViewModel.關閉客製化使用者對話窗控制項();
            }
        }

        private void 點選遮罩()
        {
            處理中ViewModel.關閉忙碌中使用者控制項();
        }

        private async void 處理中遮罩()
        {
            處理中ViewModel.顯示忙碌中使用者控制項("正在更新資料", "正在更新資料,需要2秒鐘");
            await Task.Delay(2000);
            處理中ViewModel.關閉忙碌中使用者控制項();
        }

        private void 客製化對話窗()
        {
            客製化使用者對話窗ViewModel.顯示客製化使用者對話窗控制項("請進行身分驗證", "請輸入您的帳號與密碼,並且點選確定按鈕");
        }

        public void OnNavigatedFrom(NavigationParameters parameters)
        {

        }

        public void OnNavigatedTo(NavigationParameters parameters)
        {
        }
    }
}

沒有留言:

張貼留言