Xamarin Forms - 简化验证






4.90/5 (13投票s)
本文假定您具备 C# 和 Xamarin Forms 的基础知识,并将演示如何通过应用在模型上的简单数据注释来实现 Xamarin Forms 验证。
引言
最近,我们为一位客户开始使用 Xamarin Forms 构建一个移动应用程序,以支持 iOS 和 Android 设备。我们需要考虑的一个设计方面是表单验证。
我们对表单验证有以下设计目标:
- 所有字段验证(如必填、电子邮件)都应在提交表单时完成。如果验证失败,验证消息应显示在每个字段下方。
- 由于我们有来自 ASP.NET MVC 技术的开发人员,并且他们刚接触 Xamarin Forms,因此验证设计应易于实现且跨技术保持一致。
- 与 ASP.NET MVC 一样,在 Xamarin Forms 中应遵循 数据注释验证。
本文假定您具备 C# 和 Xamarin Forms 的基础知识,并将演示如何通过应用在模型上的简单数据注释来实现 Xamarin Forms 验证。
先决条件
您需要最新版本的 Visual Studio 2017,并安装 Xamarin 工作负载和模拟器。
步骤 1 – 创建新的 Xamarin Forms 项目
让我们开始使用 Visual Studio 2017 创建一个新的 Xamarin Forms 项目,选择 **文件** -> **新建** -> **项目**。
在“新建项目”窗口中,选择“跨平台”->“移动应用(Xamarin Forms)”,如下图所示:
将项目名称输入为 Validation Demo,然后点击 **确定**,将显示以下选项对话框:
在上面的屏幕中,选择“空白项目”并点击 **确定**,将创建以下项目:
选择模拟器并运行项目,您应该能够看到带有欢迎文本的 **主页**,如下所示:
步骤 2 – 使用 XAML 创建登录页面
为了我们的验证示例,我们将在 `MainPage.xaml` 中添加两个输入字段(`Username` 和 `Password`)以及一个 **Login** 按钮。
我们将在提交表单时实施以下验证逻辑:
- 字段 `Username` 是必填的。
- 字段 `Username` 应该是有效的电子邮件地址。
- 字段 `username` 的最大长度应为 20 个字符。
- 字段 `Password` 是必填的。
让我们打开 `MainPage.xaml` 并按如下方式修改 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:local="clr-namespace:ValidationsDemo"
x:Class="ValidationsDemo.MainPage">
<StackLayout Padding="20">
<Label Text="Login" HorizontalOptions="Center" FontSize="50"/>
<Label Text="{Binding Message}"
IsVisible="False" TextColor="Red"/>
<Label Text="Username"/>
<Entry Text="{Binding LoginModel.Username}"/>
<Label x:Name="LoginModel_UsernameError"
IsVisible="False" TextColor="Red" />
<Label Text="Password" />
<Entry IsPassword="true" Text="{Binding LoginModel.Password}"/>
<Label x:Name="LoginModel_PasswordError"
IsVisible="False" TextColor="Red" />
<StackLayout Orientation="Horizontal">
<Switch IsToggled="{Binding LoginModel.RememberMe}"
HorizontalOptions="Start" />
<Label Text="Remember"
HorizontalOptions="FillAndExpand" VerticalTextAlignment="Center"/>
</StackLayout>
<Button Text="Login"
Command="{Binding LoginInCommand}" BackgroundColor="LightBlue" />
</StackLayout>
</ContentPage>
注意:为了使我们的验证生效,我们在每个输入字段下方添加了错误标签,其命名约定为 **Entry Binding Field Name Error
**。将“.”替换为“_”。
步骤 3 – 创建登录模型类
创建 **Login Model** 类,它将保存我们的验证逻辑,如下所示。请确保向项目添加 `System.ComponentModel.Annotations` Nuget 包。
using System.ComponentModel.DataAnnotations;
namespace ValidationsDemo.Model
{
public class LoginModel
{
[Required, MaxLength(20), EmailAddress]
public string Username { get; set; }
[Required]
public string Password { get; set; }
public bool RememberMe { get; set; }
}
}
注意:在上面的模型中,我们使用 `Required、MaxLength(20) 和 EmailAddress` 属性将所有验证需求作为数据注释应用。
步骤 4 – 创建视图模型类
由于 Xamarin Forms 建议使用 MVVM 模式,我们将创建一个名为 `MainPageViewModel.cs` 的视图模型类,如下所示:
namespace ValidationsDemo.ViewModel
{
public class MainPageViewModel
{
public LoginModel LoginModel { get; set; } = new LoginModel();
public ICommand LoginInCommand { get; }
private Page _page;
public MainPageViewModel(Page page)
{
_page = page;
LoginInCommand = new Command(async () => await LoginAsync());
}
private async Task LoginAsync()
{
if (!ValidationHelper.IsFormValid(LoginModel, _page)) { return; }
await _page.DisplayAlert("Success", "Validation Success!", "OK");
}
}
}
注意:在上面的代码中,在 `LoginAsync` 命令中,我们有 `ValidationHelper.IsFormValid(LoginModel, _page)` 代码,它将根据验证属性对表单进行所有魔鬼般的验证。我们将在下一节中详细介绍 Validation Helper 类。
步骤 5 – 将视图模型类绑定到页面
打开 `MainPage.xaml.cs` 文件,只需将 `ViewModel` 类实例分配给 Main Page 的 Binding Context,如下所示:
using ValidationsDemo.ViewModel;
using Xamarin.Forms;
namespace ValidationsDemo
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
this.BindingContext = new MainPageViewModel(this);
}
}
}
步骤 6 – 创建验证助手类
创建一个名为 `ValidationHelper` 的新类,并添加一个签名如下的 `public` 方法 `IsFormValid`:
public static class ValidationHelper
{
public static bool IsFormValid(object model, Page page)
{
HideValidationFields(model, page);
var errors = new List<ValidationResult>();
var context = new ValidationContext(model);
bool isValid = Validator.TryValidateObject(model, context, errors, true);
if (!isValid)
{
ShowValidationFields(errors, model, page);
}
return errors.Count() == 0;
}
private static void HideValidationFields
(object model, Page page, string validationLabelSuffix = "Error")
{
if (model == null) { return; }
var properties = GetValidatablePropertyNames(model);
foreach (var propertyName in properties)
{
var errorControlName =
$"{propertyName.Replace(".", "_")}{validationLabelSuffix}";
var control = page.FindByName<Label>(errorControlName);
if (control != null)
{
control.IsVisible = false;
}
}
}
private static void ShowValidationFields
(List<ValidationResult> errors,
object model, Page page, string validationLabelSuffix = "Error")
{
if (model == null) { return; }
foreach (var error in errors)
{
var memberName = $"{model.GetType().Name}_{error.MemberNames.FirstOrDefault()}";
memberName = memberName.Replace(".", "_");
var errorControlName = $"{memberName}{validationLabelSuffix}";
var control = page.FindByName<Label>(errorControlName);
if (control != null)
{
control.Text = $"{error.ErrorMessage}{Environment.NewLine}";
control.IsVisible = true;
}
}
}
private static IEnumerable<string> GetValidatablePropertyNames(object model)
{
var validatableProperties = new List<string>();
var properties = GetValidatableProperties(model);
foreach (var propertyInfo in properties)
{
var errorControlName = $"{propertyInfo.DeclaringType.Name}.{propertyInfo.Name}";
validatableProperties.Add(errorControlName);
}
return validatableProperties;
}
private static List<PropertyInfo> GetValidatableProperties(object model)
{
var properties = model.GetType().GetProperties().Where(prop => prop.CanRead
&& prop.GetCustomAttributes(typeof(ValidationAttribute), true).Any()
&& prop.GetIndexParameters().Length == 0).ToList();
return properties;
}
}
步骤 7 – 运行项目并测试验证
我们已经完成了基本的表单验证实现,现在是时候进行测试了。让我们通过定位可用的模拟器来运行项目,您应该会看到下面的登录屏幕。要执行各种测试用例,请单击“登录”按钮。
关注点
在 XAML 页面中每个输入字段下方插入具有正确命名约定的错误标签,并调用 `ValidationHelper.IsFormValid` 将实现我们的验证。
历史
- 2019年1月19日:初始版本
这是我的第一篇文章,希望您能通过使用验证助手节省时间。