c# - 如何将 ViewModel 属性验证与 ViewModel 分离?

标签 c# wpf oop mvvm mvvm-light

我正在使用 MVVMLight。这是我的 Department 模型/POCO 类。我不想以任何方式污染它。

 public partial class Department
    {
        public int DepartmentId { get; set; }
        public string DepartmentCode { get; set; }
        public string DepartmentFullName { get; set; }
    }

这是 CreateDepartmentViewModel:

public class CreateDepartmentViewModel : ViewModelBase
{
    private IDepartmentService departmentService;
    public RelayCommand CreateDepartmentCommand { get; private set; }

    public CreateDepartmentViewModel(IDepartmentService DepartmentService)
    {
        departmentService = DepartmentService;
        this.CreateDepartmentCommand = new RelayCommand(CreateDepartment, CanExecute);
    }

    private Department _department = new Department();
    public Department Department
    {
        get
        {
            return _department;
        }
        set
        {
            if (_department == value)
            {
                return;
            }
            _department = value;
            RaisePropertyChanged("Department");
        }
    }

    private Boolean CanExecute()
    {
        return true;
    }
    private void CreateDepartment()
    {
        bool success = departmentService.SaveDepartment(_department);
    }
}

DepartmentCodeDepartmentFullName 绑定(bind)到 UI,如下所示。

 <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <TextBlock Text="Department Code" Grid.Row="0"/>
        <TextBox Grid.Row="0" Text="{Binding Department.DepartmentCode, Mode=TwoWay}"  Margin="150,0,0,0"/>

        <TextBlock Text="Department Name" Grid.Row="1"/>
        <TextBox Grid.Row="1" Text="{Binding Department.DepartmentFullName, Mode=TwoWay}" ToolTip="Hi" Margin="150,0,0,0"/>

        <Button Grid.Row="2" Content="Save" Width="50" Command="{Binding CreateDepartmentCommand}"/>
    </Grid>

在保存部门之前,我需要验证 DepartmentCodeDepartmentFullName 中是否都有一些文本。

我的验证逻辑应该放在哪里?在 ViewModel 本身?如果是这样,我该如何解耦我的验证逻辑,以便它也可以进行单元测试?

最佳答案

我发现最简单的方法是使用

System.Windows.Controls.ValidationRule

只需要 3 个简单的步骤。

首先您创建一个 ValidationRule。这是一个完全独立的类,存在于您的模型和 ViewModel 之外,并定义了应如何验证文本数据。在这种情况下,一个简单的 String.IsNullOrWhiteSpace 检查。

public class DepartmentValidationRule : System.Windows.Controls.ValidationRule
{
    public override System.Windows.Controls.ValidationResult Validate(object value, CultureInfo ultureInfo)
    {
        if (String.IsNullOrWhiteSpace(value as string))
        {
            return new System.Windows.Controls.ValidationResult(false, "The value is not a valid");
        }
        else
        {
            return new System.Windows.Controls.ValidationResult(true, null);
        }
    }
}

接下来,通过指定文本绑定(bind)的 ValidationRules 属性,指定您的文本框应使用新类的实例对输入的文本执行验证。如果验证失败,您将获得文本框边框变为红色的额外好处。

    <TextBlock Text="Department Code" Grid.Row="0"/>
    <TextBox Name="DepartmentCodeTextBox"  Grid.Row="0" Margin="150,0,0,0">
        <TextBox.Text>
            <Binding Path="Department.DepartmentCode" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
                <Binding.ValidationRules>
                    <local:DepartmentValidationRule/>
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>
    <TextBlock Text="Department Name" Grid.Row="1"/>
    <TextBox Name="DepartmentNameTextBox" Grid.Row="1" ToolTip="Hi" Margin="150,0,0,0">
        <TextBox.Text>
            <Binding Path="Department.DepartmentFullName" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
                <Binding.ValidationRules>
                    <local:DepartmentValidationRule/>
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>

最后,创建一个样式以在任一 TextBox 验证失败时禁用“保存”按钮。我们通过绑定(bind)到将验证规则绑定(bind)到的文本框的 Validation.HasError 属性来执行此操作。我们将这种样式命名为 DisableOnValidationError 只是为了让事情显而易见。

    <Grid.Resources>
        <Style x:Key="DisableOnValidationError" TargetType="Button">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=(Validation.HasError), ElementName=DepartmentCodeTextBox}" Value="True" >
                    <Setter Property="IsEnabled" Value="False"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding Path=(Validation.HasError), ElementName=DepartmentNameTextBox}" Value="True" >
                    <Setter Property="IsEnabled" Value="False"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Grid.Resources>

最后我们在保存按钮上设置 DisableOnValidationError 样式

    <Button Grid.Row="2" Content="Save" Width="50" Command="{Binding CreateDepartmentCommand}"
            Style="{StaticResource DisableOnValidationError}"/>

现在,如果您的任何一个 TextBox 验证失败,TextBox 将突出显示并且 Save 按钮将被禁用。

DepartmentValidationRule 完全独立于您的业务逻辑,并且可重复使用和测试。

关于c# - 如何将 ViewModel 属性验证与 ViewModel 分离?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18958801/

相关文章:

java - 类构造函数中的抽象方法

c# - 合并运算符 - 用法 (c#)

c# - 如何链接2个组合框

c# - WPF 4.5 DataGrids 的 INotifyDataErrorInfo 是否损坏

wpf - 在WPF中,是否有任何方法可以将两个Style合并为一个控件?

java - 在类之间传递有意义的消息的方法?

c# - 从下拉列表中选择项目时更改 ComboBox 的文本字段?

c# - 如何在 C# 中短路 'or' 赋值?

c# - DateTime.ToUniversalTime() 如何工作?

PHP OOP 自动加载类命名空间问题