Проверка с использованием MVVM Light в универсальном приложении Windows
После настройки MVVM Light в приложении Universal Windows App у меня есть следующая структура, и мне интересно, какой самый чистый способ сделать проверку в 2017 году с помощью UWP и mvvmlight для уведомления пользователей с ошибками и, возможно, reset значение текстового поля, когда это необходимо. Единственный трюк в том, что текстовое поле является частью UserControl (для ясности очищено ненужный код xaml), поскольку он будет использоваться несколько раз. Также я добавил DataAnnotations и ValidationResult для демонстрации, а не для того, чтобы предположить, что это лучший способ сделать это или что он работает каким-либо образом до сих пор.
Код работает отлично, поскольку привязка и добавление и удаление значений
-
ViewModel
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
<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>
-
Код UserControl Behind:
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));
}
Ответы
Ответ 1
Обычно мы используем интерфейс IDialogService
в MVVM Light для уведомления пользователей с ошибками, есть метод ShowError
, метод ShowMessage
и ShowMessageBox
в IDialogService
.
Мы должны иметь возможность создать экземпляр PropertyMetadata с PropertyChangedCallback, он будет вызываться, когда эффективное значение свойства свойства зависимостей изменения. Когда он вызывается, мы можем использовать в нем метод 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);
}
}
}
Также, если вы хотите reset значение TextBox
, вы должны использовать RaisePropertyChanged
в свойстве Age. Если мы не используем RaisePropertyChanged
в свойстве Age, значение TextBox не изменится при изменении значения Age.
Подробнее о RaisePropertyChanged см. интерфейс INotifyPropertyChanged.
Например:
public int Age
{
get { return _age; }
set
{
if ((value > 1) && (value <= 100))
_age = value;
RaisePropertyChanged("Age");
}
}
Update:
На вашей странице вы должны добавить для добавления 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>
Ответ 2
Здесь вам не хватает вызова функции Validator.ValidateObject, чтобы выполнить фактическую проверку. Это применит атрибуты проверки к данным и также вызовет IValidatableObject.Validate, если вы его внедрили (вы должны реализовать это вместо наличия специальных функций, таких как ValidateAge).
Вот так:
// Validate using:
// 1. ValidationAttributes attached to this validatable class, and
// 2. ValidationAttributes attached to the properties of this validatable 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));