XAML in Xamarin.Forms 基礎篇 電子書

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

Xamarin.Forms 快速入門 電子書

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

2016/10/24

Xamarin.Forms 開發一個可以反覆使用的使用者控制項 User Control

在這份筆記中,將會開發一個可以反覆使用的使用者控制項 User Control的專案範例。
當在頁面中使用這個擴充使用者控制項的時候,可以透過 ViewModel 來定義這個使用者控制項的類型與商業處理邏輯,例如,在底下的範例中,將設定這個使用者自訂控制項為一個可以輸入身分證字號的文字輸入盒,當尚未輸入任何身分證字號的時候,會自動出現 請輸入身分證字號 這個浮水印文字,當正在輸入身分證字號的時候,只要輸入的文字不符合身分證字號規範,此時,最右方會出現紅色底的 X 警告提示;若輸入的文字就是一個身分證字號,那麼,最右方會出現綠色底的 V 打勾視覺,表示現在這個欄位輸入一個符合規定的內容。
下面動畫圖片,呈現了應用程式執行的時候,實際操作的過程。
這個是範例專案
想要做出這樣的效果,您需要先建立一個 ContentPage 頁面,並且修正根節點為 ContentView,記得,Code Behind 的部分,要修改繼承類別,從 ContentPage 為 ContentView。
由於這個範例專案,不論在 XAML 與 C# ViewModel 上,都有加入適當的註解,所以,就不再多做解釋;若您對於這個範例專案做法有問題,歡迎提出來討論。

使用者控制項 - 具有輸入格式檢查能力

這個使用者控制項的 XAML 定義如下

MyEntry.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="UserCtrlEntry.UserControls.MyEntry">
    <Grid
        RowSpacing="0" ColumnSpacing="0"
        >
        <!--這個 Grid 切割成兩個垂直列,前者佔據剩下所有空間,後者佔據 50單位-->
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="50" />
        </Grid.ColumnDefinitions>

        <!--使用者輸入文字地方的底色設定-->
        <BoxView 
            Grid.Row="0" Grid.Column="0"
            VerticalOptions="Fill" HorizontalOptions="Fill"
            Color="#44f4dda6"
            />

        <!--使用者輸入文字的控制項,會自動依類型顯示浮水印文字-->
        <Entry
            Grid.Row="0" Grid.Column="0"
            Placeholder="{Binding MyPlaceholder}" 
            Text="{Binding MyEntryText}"
            />

        <!--提示輸入內容是否正確的顏色方框,紅色,輸入錯誤,綠色,輸入格是正確-->
        <BoxView 
            Grid.Row="0" Grid.Column="1"
            WidthRequest="50"
            VerticalOptions="Fill"
            Color="{Binding ValueCorrectBoxBackground}"
            />

        <!--標是這個文字輸入是否正確,正確:V 不正確:X-->
        <Label
            Grid.Row="0" Grid.Column="1"
            HorizontalOptions="Center" VerticalOptions="Center"
            FontAttributes="Bold"
            FontSize="Large"
            TextColor="White"
            Text="{Binding ValueCorrectSymbol}" />
    </Grid>
</ContentView>
這個使用者控制項用的 ViewModel 如下

MyEntryViewModel.cs

using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Xamarin.Forms;

namespace UserCtrlEntry.ViewModels
{
    public class MyEntryViewModel : BindableBase
    {

        #region MyPlaceholderType
        private string _MyPlaceholderType;
        /// <summary>
        /// 這個文字輸入盒的類型,指定不同的類型,文字輸入盒會有不同的能力表現出來
        /// </summary>
        public string MyPlaceholderType
        {
            get { return this._MyPlaceholderType; }
            set { this.SetProperty(ref this._MyPlaceholderType, value); }
        }
        #endregion

        #region MyPlaceholder
        private string _MyPlaceholder;
        /// <summary>
        /// 文字輸入盒沒有任何文字輸入的時候,要顯示甚麼浮水印文字
        /// </summary>
        public string MyPlaceholder
        {
            get { return this._MyPlaceholder; }
            set { this.SetProperty(ref this._MyPlaceholder, value); }
        }
        #endregion

        #region ValueCorrect
        private bool _ValueCorrect;
        /// <summary>
        /// 輸入文字的格式驗證是否正確
        /// </summary>
        public bool ValueCorrect
        {
            get { return this._ValueCorrect; }
            set { this.SetProperty(ref this._ValueCorrect, value); }
        }
        #endregion

        #region ValueCorrectSymbol
        private string _ValueCorrectSymbol;
        /// <summary>
        /// 要顯示格式是否正確的文字,要更漂亮,可以使用圖片或者 Font Awesome取代
        /// </summary>
        public string ValueCorrectSymbol
        {
            get { return this._ValueCorrectSymbol; }
            set { this.SetProperty(ref this._ValueCorrectSymbol, value); }
        }
        #endregion

        #region MyEntryText
        private string _MyEntryText;
        /// <summary>
        /// 儲存使用者輸入文字的地方
        /// </summary>
        public string MyEntryText
        {
            get { return this._MyEntryText; }
            set
            {
                this.SetProperty(ref this._MyEntryText, value);
                if (MyPlaceholderType == "Name")
                {
                    if (MyEntryText.Length < 6)
                    {
                        ValueCorrect = false;
                    }
                    else
                    {
                        ValueCorrect = true;
                    }
                    更新文字格式驗證符號與背景顏色();
                }
                else if (MyPlaceholderType == "ID")
                {
                    ValueCorrect = 驗證身份證字號格式(MyEntryText);
                    更新文字格式驗證符號與背景顏色();
                }
                else if (MyPlaceholderType == "Email")
                {
                    ValueCorrect = 驗證電子郵件格式(MyEntryText);
                    更新文字格式驗證符號與背景顏色();
                }
            }
        }
        #endregion

        #region ValueCorrectBoxBackground
        private Color _ValueCorrectBoxBackground;
        /// <summary>
        /// 使用者輸入文字格式是否正確的背景顏色定義
        /// </summary>
        public Color ValueCorrectBoxBackground
        {
            get { return this._ValueCorrectBoxBackground; }
            set { this.SetProperty(ref this._ValueCorrectBoxBackground, value); }
        }
        #endregion


        public MyEntryViewModel()
        {
            // 進行建構式的屬性初始化
            ValueCorrect = false;
            ValueCorrectSymbol = "X";
            MyPlaceholderType = "";
            MyEntryText = "";
            ValueCorrectBoxBackground = Color.Red;
        }

        public void 更新文字格式驗證符號與背景顏色()
        {
            if (ValueCorrect == false)
            {
                ValueCorrectSymbol = "X";
                ValueCorrectBoxBackground = Color.Red;
            }
            else
            {
                ValueCorrectSymbol = "V";
                ValueCorrectBoxBackground = Color.Green;
            }
        }
        public void 更新文字輸入盒的浮水印文字設定(string pMyPlaceholderType)
        {
            MyPlaceholderType = pMyPlaceholderType;
            if (MyPlaceholderType == "Name")
            {
                MyPlaceholder = "請輸入姓名";
            }
            else if (MyPlaceholderType == "ID")
            {
                MyPlaceholder = "請輸入身分證字號";
            }
            else if (MyPlaceholderType == "Email")
            {
                MyPlaceholder = "請輸入電子郵件信箱";
            }
            else
            {
                MyPlaceholder = "";
            }
        }

        public bool 驗證身份證字號格式(string arg_Identify)
        {
            var d = false;
            if (arg_Identify.Length == 10)
            {
                arg_Identify = arg_Identify.ToUpper();
                if (arg_Identify[0] >= 0x41 && arg_Identify[0] <= 0x5A)
                {
                    var a = new[] { 10, 11, 12, 13, 14, 15, 16, 17, 34, 18, 19, 20, 21, 22, 35, 23, 24, 25, 26, 27, 28, 29, 32, 30, 31, 33 };
                    var b = new int[11];
                    b[1] = a[(arg_Identify[0]) - 65] % 10;
                    var c = b[0] = a[(arg_Identify[0]) - 65] / 10;
                    for (var i = 1; i <= 9; i++)
                    {
                        b[i + 1] = arg_Identify[i] - 48;
                        c += b[i] * (10 - i);
                    }
                    if (((c % 10) + b[10]) % 10 == 0)
                    {
                        d = true;
                    }
                }
            }
            return d;
        }

        public bool 驗證電子郵件格式(string strIn)
        {
            // Return true if strIn is in valid e-mail format.
            return Regex.IsMatch(strIn,
                   @"^(?("")("".+?""@)|(([0-9a-zA-Z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-zA-Z])@))" +
                   @"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,6}))$");
        }
    }
}

使用剛剛建立的使用者控制項頁面

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:UserCtrlEntry.UserControls"
             x:Class="UserCtrlEntry.Views.MainPage"
             Title="MainPage">
    <StackLayout 
        Margin="20,0"
        HorizontalOptions="Center" VerticalOptions="Center">
        <Label Text="使用者控制項與商業邏輯包裝範例" HorizontalOptions="Center" />
        <!--宣告一個使用者控制項,並且綁定 ViewModel 內的 Name Property,設定這個文字輸入盒,具有輸入字串長度檢查能力-->
        <UserControls:MyEntry BindingContext="{Binding Name}"/>
        <!--宣告一個使用者控制項,並且綁定 ViewModel 內的 ID Property,設定這個文字輸入盒,具有輸入身分證字號檢查能力-->
        <UserControls:MyEntry BindingContext="{Binding ID}"/>
        <!--宣告一個使用者控制項,並且綁定 ViewModel 內的 Email Property,設定這個文字輸入盒,具有輸入電子郵件格式檢查能力-->
        <UserControls:MyEntry BindingContext="{Binding Email}"/>
    </StackLayout>
</ContentPage>

MainPageViewModel.cs

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

namespace UserCtrlEntry.ViewModels
{
    public class MainPageViewModel : BindableBase, INavigationAware
    {
        private string _title;
        public string Title
        {
            get { return _title; }
            set { SetProperty(ref _title, value); }
        }


        #region Name
        private MyEntryViewModel _Name;
        /// <summary>
        /// 這個屬性,將會用於綁定到 姓名 欄位輸入
        /// </summary>
        public MyEntryViewModel Name
        {
            get { return this._Name; }
            set { this.SetProperty(ref this._Name, value); }
        }
        #endregion


        #region ID
        private MyEntryViewModel _ID;
        /// <summary>
        /// 這個屬性,將會用於綁定到 身分證字號 欄位輸入
        /// </summary>
        public MyEntryViewModel ID
        {
            get { return this._ID; }
            set { this.SetProperty(ref this._ID, value); }
        }
        #endregion


        #region Email
        private MyEntryViewModel _Email;
        /// <summary>
        /// 這個屬性,將會用於綁定到 電子郵件 欄位輸入
        /// </summary>
        public MyEntryViewModel Email
        {
            get { return this._Email; }
            set { this.SetProperty(ref this._Email, value); }
        }
        #endregion


        public MainPageViewModel()
        {
            // 進行三個文字輸入盒要綁定的 ViewModel 的物件初始化
            Name = new MyEntryViewModel();
            Name.更新文字輸入盒的浮水印文字設定("Name");
            ID = new MyEntryViewModel();
            ID.更新文字輸入盒的浮水印文字設定("ID");
            Email = new MyEntryViewModel();
            Email.更新文字輸入盒的浮水印文字設定("Email");
        }

        public void OnNavigatedFrom(NavigationParameters parameters)
        {

        }

        public void OnNavigatedTo(NavigationParameters parameters)
        {
            if (parameters.ContainsKey("title"))
                Title = (string)parameters["title"] + " and Prism";
        }
    }
}

沒有留言:

張貼留言