Xamarin Forms Prism 於ViewModel使用MVC的Model驗證
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