Xamarin Xamarin Forms

Xamarin Forms Prism 於ViewModel使用MVC的Model驗證

張阿鬼 2019/12/31 11:55:44
363

APP撰寫時,常常會有需要驗證的欄位,
像是以下這樣的畫面:

    <StackLayout  VerticalOptions="CenterAndExpand" Padding="100,60">
        <Entry Text="{Binding Id}" Placeholder="請輸入帳號"/>
        <Entry Text="{Binding Pwd}" Placeholder="請輸入密碼" IsPassword="True" />
        <Button Text="登入" Command="{Binding OnLogin}" />
    </StackLayout>



在MVVM的模式下,會在登入的按鈕按下後,
於對應的Command撰寫這樣的程式碼:

            this.OnLogin = new DelegateCommand(() =>
              {
                  if (string.IsNullOrEmpty(this.Id))
                  {
                      pageDialogService.DisplayAlertAsync("訊息", "請輸入帳號", "OK");
                      return;
                  }

                  if (string.IsNullOrEmpty(this.Pwd))
                  {
                      pageDialogService.DisplayAlertAsync("訊息", "請輸入密碼", "OK");
                      return;
                  }

                  //....

              });


當欄位少的時候,還算方便閱讀,
但一旦需要驗證必填的欄位變多,且有些欄位甚至有要求格式,
這些程式碼一下子就會變得非常多。
但如果能像MVC一些使用Model驗證的方式,如下:

        [Required(ErrorMessage ="請輸入帳號")]
        public string Id { get; set; }

        [Required(ErrorMessage = "請輸入密碼")]
        public string Pwd { get; set; }


這樣撰寫出來不但容易辨識跟閱讀,同時也大量減少了許多驗證相關的程式碼。
在ViewModel中當然我們也可以實作相同的驗證機制,而且不限定在Prism中使用。

首先我們必須為ViewModel所在的專案安裝System.ComponentModel.Annotations套件:


接著要在ViewModel中,撰寫時做驗證Model的方法:

        public  List<ValidationResult> Valid()
        {
            ValidationContext context = new ValidationContext(this);
            List<ValidationResult> resultList = new List<ValidationResult>();
            Validator.TryValidateObject(this, context, resultList, true);
            return resultList;
        }

在這個方法中會返回一個集合,
該集合表示驗證不通過屬性,以及其錯誤訊息。
所以我們可以再寫一個方法,把錯誤Alert出來:

        public async  Task<bool> ValidAndAlert(IPageDialogService pageDialogService)
        {
            var result = this.Valid().ToList();
            if (result.Any())
            {
                var message = String.Join(Environment.NewLine, result.Select(c => c.ErrorMessage));
                await pageDialogService.DisplayAlertAsync("訊息", message, "OK");
            }
            return result.Count == 0;
        }

方法中我們將錯誤訊息使用換行符號將所有錯誤Join起來成一個字串,
最後retunr一個布林值表示這個Model驗證是否有錯誤。

所以原本按下登入的Command就可以更改成這樣:

            this.OnLogin = new DelegateCommand(async () =>
              {
                  if(await this.ValidAndAlert(pageDialogService))
                  {
                      //..驗證通過要做的事情
                  }
              });


實做後的結果:


除了Required之外,當然我們也可以用在MVC中許多的驗證,
像是使用正規表示式RegularExpression:

        [Required(ErrorMessage ="請輸入帳號")]
        [RegularExpression(@"^[0-9]*$",ErrorMessage ="帳號必須為數字")]
        public string Id { get; set; }

或者有多國語系的需求需要讀取使用resx檔


基本上在MVC上能做到的驗證,
使用這樣的方式也幾乎都能做到。
而且由於驗證的程式是我們自行撰寫的,
所以也可以針對他去做更多的客製化,比如兩個欄位其中一個有填就行之類的,就可以從Valid方法中著手。

或者我們一樣也可以自行定義客製化的ValidationAttribute

        [Required(ErrorMessage ="請輸入帳號")]
        [RegularExpression(@"^[0-9]*$",ErrorMessage ="帳號必須為數字")]
        [IdTest]
        public string Id { get; set; }
    public class IdTestAttribute : ValidationAttribute
    {
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
         
            //這裡做要驗證的事情
            return ValidationResult.Success;
        }
    }


有了Model驗證,又大大提升了使用MVVM架構的好處!

範例連結
https://github.com/stevenchang0529/Xamarin.Lab.PrismModelValid

張阿鬼