After done with setting up MVVM Light in a Universal Windows App application, I have the following structure, and I wonder what is the cleanest way to do validation in 2017 using UWP and mvvmlight to notify users with errors and possibly reset the textbox value when needed. The only trick is that the Textbox is part of a UserControl (cleaned up unnecessary xaml code for clarity) since it will be used multiple times. Also I added DataAnnotations and ValidationResult for demonstration and not to suggest that this is the best way to do it or that it is working in any way so far.
The code works fine as far as binding and adding and removing values
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;
}
}
View
<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 Code 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));
}
We usually use IDialogService
interface in MVVM Light to notify users with errors, there are ShowError
method, ShowMessage
method and ShowMessageBox
method in IDialogService
.
We should be able to new a PropertyMetadata instance with a PropertyChangedCallback value, it will be invoked when the effective property value of a dependency property changes. When it is invoked, we can use the ShowMessage
method in it.
For example:
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);
}
}
}
Also if you want to reset the TextBox
value, you should be able to use RaisePropertyChanged
in the Age property. If we do not use RaisePropertyChanged
in the Age property, the TextBox value will not change when the Age value has changed.
For more info about the RaisePropertyChanged, please refer INotifyPropertyChanged interface.
For example:
public int Age
{
get { return _age; }
set
{
if ((value > 1) && (value <= 100))
_age = value;
RaisePropertyChanged("Age");
}
}
Update:
In your Page you should be add to add DataContext in your control.
<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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With