在通用Windows应用程序中使用MVVM Light进行验证

时间:2017-02-03 18:41:47

标签: c# xaml mvvm win-universal-app mvvm-light

完成在通用Windows应用程序中设置MVVM Light后,我有以下结构,我想知道在2017年使用UWP和mvvmlight进行验证的最简洁方法是通知用户有错误并可能重置文本框需要时的价值。唯一的技巧是Textbox是UserControl的一部分(为了清楚起见,清理了不必要的xaml代码),因为它将被多次使用。我还添加了DataAnnotations和ValidationResult用于演示,而不是建议这是最好的方法,或者它到目前为止以任何方式工作。

就绑定和添加和删除值而言,代码工作正常

  • 视图模型

    using GalaSoft.MvvmLight;
    using GalaSoft.MvvmLight.Command;
    using GalaSoft.MvvmLight.Views;
    using System;
    using System.ComponentModel.DataAnnotations;
    
    public class ValidationTestViewModel : ViewModelBase
     {
       private int _age;
    
      [Required(ErrorMessage = "Age is required")]
      [Range(1, 100, ErrorMessage = "Age should be between 1 to 100")]
      [CustomValidation(typeof(int), "ValidateAge")]
      public int Age
        {
          get { return _age; }
          set
          {
            if ((value > 1) && (value =< 100))
                _age= value;
          }
        }
    
      public static ValidationResult ValidateAge(object value, ValidationContext validationContext)
       {
          return null;
       }
    }
    
  • 查看

    <Page
     x:Class="ValidationTest.Views.ValidationTestPage"
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     xmlns:local="using:ValidationTest.Views"
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
     DataContext="{Binding ValidationTestPageInstance, Source={StaticResource  Locator}}" 
    xmlns:views="using:ValidationTest.Views">
    
         <views:NumberEdit TextInControl="{Binding Age, Mode=TwoWay}" />
    
    </Page>
    
  • 用户控件

    <UserControl
     x:Class="ValidationTest.Views.Number"
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     xmlns:local="using:ValidationTest.Views"
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
     x:Name="userControl1">
      <Grid>
    
      <TextBox x:Name="content" Text="{Binding TextInControl, ElementName=userControl1, Mode=TwoWay}"></TextBox>
       </Grid>
    
     </UserControl>
    
  • 用户控制代码

    public partial class NumberEdit : UserControl
    {
       public string TextInControl
          {
            get { return (string)GetValue(TextInControlProperty); }
            set {
                  SetValue(TextInControlProperty, value);
                }
    }
    
    public static readonly DependencyProperty TextInControlProperty =
        DependencyProperty.Register("TextInControl", typeof(string),
                                       typeof(NumberEdit), new PropertyMetadata(null));
    
     }
    

2 个答案:

答案 0 :(得分:2)

我们通常在MVVM Light中使用IDialogService接口来通知用户有错误,ShowError中有ShowMessage方法,ShowMessageBox方法和IDialogService方法。

我们应该能够创建一个PropertyChangedCallback值的PropertyMetadata实例,它将在依赖项属性的有效属性值更改时调用。调用它时,我们可以在其中使用ShowMessage方法。

例如:

public sealed partial class NumberEdit : UserControl
{
    public NumberEdit()
    {
        this.InitializeComponent();
    }

    public static readonly DependencyProperty TextInControlProperty =
     DependencyProperty.Register("TextInControl", typeof(string),
                                    typeof(NumberEdit), new PropertyMetadata(null, new PropertyChangedCallback(StringChanged)));

    private static void StringChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        int value;
        Int32.TryParse(e.NewValue.ToString(), out value);
        if (0 < value && value < 99)
        {
        }
        else
        {
            var dialog = ServiceLocator.Current.GetInstance<IDialogService>();
            dialog.ShowMessage("Age should be between 1 to 100", "Error mesage");
        }
    }

    public string TextInControl
    {
        get { return (string)GetValue(TextInControlProperty); }
        set
        {
            SetValue(TextInControlProperty, value);
        }
    }
}

此外,如果您要重置TextBox值,则应该可以在Age属性中使用RaisePropertyChanged。如果我们在Age属性中不使用RaisePropertyChanged,则在Age值更改时TextBox值不会更改。

有关RaisePropertyChanged的更多信息,请参阅INotifyPropertyChanged interface

例如:

public int Age
{
    get { return _age; }
    set
    {
        if ((value > 1) && (value <= 100))
            _age = value;
        RaisePropertyChanged("Age");
    }
}

更新

在您的页面中,您应该添加以在控件中添加DataContext。

<Page x:Class="Validation_Using_MVVM_Light_in_a.SecondPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d"
      xmlns:local="using:Validation_Using_MVVM_Light_in_a"
xmlns:VM="using:Validation_Using_MVVM_Light_in_a.ViewModel">

    <Page.Resources>
        <VM:ValidationTestViewModel x:Key="MyViewModel" />
    </Page.Resources>
    <Grid>
        <local:NumberEdit  DataContext="{StaticResource MyViewModel}"  TextInControl="{Binding Age, Mode=TwoWay}" />
    </Grid>
</Page>

答案 1 :(得分:0)

这里缺少的是调用Validator.ValidateObject来进行实际验证。这将验证属性应用于数据,并且如果已实现它也将调用IValidatableObject.Validate(您应该实现此而不是使用诸如ValidateAge之类的特殊功能)。

像这样:

        // Validate using:
        // 1. ValidationAttributes attached to this validatable's class, and
        // 2. ValidationAttributes attached to the properties of this validatable's class, and 
        // 3. this.Validate( validationContext)
        // 
        // Note, for entities, a NotSupportedException will be thrown by TryValidateObject if any of 
        // the primary key fields are changed. Correspondingly the UI should not allow modifying 
        // primary key fields. 
        ValidationContext validationContext = new ValidationContext(this);
        List<ValidationResult> validationResults = new List<ValidationResult>(64);
        bool isValid = Validator.TryValidateObject( this, validationContext, validationResults, true);
        Debug.Assert(isValid == (validationResults.Count == 0));