【问题标题】:Validation Using MVVM Light in a Universal Windows App在通用 Windows 应用程序中使用 MVVM Light 进行验证
【发布时间】:2017-06-21 05:19:00
【问题描述】:

在通用 Windows 应用程序应用程序中设置 MVVM Light 后,我​​有以下结构,我想知道在 2017 年使用 UWP 和 mvvmlight 来通知用户错误并可能重置文本框的最干净的方法是什么需要时的价值。唯一的技巧是文本框是 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));
    
     }
    

【问题讨论】:

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


    【解决方案1】:

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

    我们应该能够用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>
    

    【讨论】:

    • XAML 中是否需要进行任何更改?此外,PropertyChangedCallback 链接不起作用
    • @usefulBee 您应该可以将DataContext 添加到页面或控件中,并且我已经更新了 StringChanged 方法中的代码。
    • @MatthewOptionalMeehan 感谢您的验证。我就这个问题提出了一个新问题:stackoverflow.com/q/42254366/2093880
    • 对这种方法的一些担忧:1) 我发现使用 RaisePropertyChanged 没有任何好处,删除它不会影响任何事情 2) 当所有这些都可以从 ViewModel 完成时,为什么要在代码后面使用 StringChanged,因为所有属性在那里声明? 3) 显示对话框消息缺乏即时验证,因为它取决于用户首先将焦点从文本框移开 4) 即使使用 RaisePropertyChanged,文本框值也永远不会重置为旧值,即使使用双向绑定模式。
    【解决方案2】:

    您在这里缺少的是调用 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));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-06-16
      • 2016-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多