I use MVVM because I honestly think that MVC is too old for modern graphical interfaces, it's fine for more static things like the web.
I'll explain how I validate my projects.
The base class I use for my ViewModels implements the IDataErrorInfo interface and I use the dataannotations to validate, here is an example of a ViewModel in my MVVM framework:
public class PersonaViewModel : ViewModel
{
readonly DateTime MinDate = new DateTime(1940, 01,01);
readonly DateTime MaxDate = DateTime.Today;
// constructor
public PersonaViewModel()
{
// la propiedad "Edad" se recalcula automáticamente cada que la propiedad FechaNacimiento cambia de valor, es como en excel cuando le pones fórmula a una celda
this.Edad = this.CreateFormula(
property: This => This.FechaNacimiento,
formula: value => DateTime.Today.AddTicks(-value.Ticks).Year - 1);
// puedeGuardar es una variable que cambia automáticamente cuando el viewmodel cambia su estado de validación
// ValidationState es una propiedad de la clase ViewModel que contiene el estado de validación del ViewModel que estás creando,
// y cambia cada vez que alguna propiedad del viewmodel es modificada
// y tiene una propiedad "HasErrors" que es true si alguna propiedad del ViewModel no pasa la validación
var puedeGuardar = this.ValidationState
.When(state => state.HasErrors == false); // puede ser !state.HasErrors pero lo pongo así por claridad
// al comando le paso "puedeGuardar" para indicar cuándo va a estar "enabled" el botón donde lo voy a bindear en la vista
this.GuardarDatos = new AsyncCommand(
method = this.Guardar,
isEnabled = puedeGuardar);
}
// este comando guarda los datos capturados
public Command GuardarDatos { get; }
[Required(ErrorMessage = "El nombre no puede estar vacío")]
[StringLength(50, ErrorMessage = "El nombre no puede tener mas de 50 caracteres")]
public string Nombre
{
get => Get<string>();
set => Set(value);
}
[ValidateMethod] // utiliza un método "IsXXXXXValid" para validad donde XXXXX es un nombre de propiedad
public DateTime FechaNacimiento
{
get => Get<DateTime>();
set => Set(value);
}
// esta propiedad se calcula automáticamente cada que la fecha de nacimiento cambia, es inicializada en el constructor
public Calculated<int> Edad { get;}
// este método valida la propiedad fechanacimiento
private bool IsFechaNacimientoValid(DateTime date)
{
return date >= MinDate && date <= MaxDate;
}
// en este método guardo los datos
private async Task Guardar()
{
// aquí guardo los datos a la base de datos
}
}
As you can see, the class inherits from ViewModel, which implements validation in its properties, in the form I only add a control type ErrotProvider (already comes standard), and I only override a method where I "bin" each property of the ViewModel with each control in the form:
// formulario, hereda de una clase Form preparada con funcionalidad para bindeo
public class PersonaView : FormBase, IView<PersonaViewModel>
{
public PersonaViewModel ViewModel { get; set; }
// dentro de la clase de mi formulario sobrecargo el método OnBinding
private override void OnBinding(Binder binder)
{
binder.Add(this.ViewModel, vm => vm.Nombre, This => This.nombreTextBox.Text);
binder.Add(this.ViewModel, vm => vm.FechaNacimiento, This => This.fechaDateTimePicker.Value);
binder.AddReadOnly(this.ViewModel, vm => vm.Edad.Value, This => This.EdadLabel.Text);
binder.AddCommand(this.ViewModel, vm => vm.GuardarDatos, This => This.btnGuardar);
}
}
And, you see, it's simple, the validation is done at the UI level, in the capture every control puts a red error message and the validation error message and the btnSave button is set to disable if any property does not pass its validation, such as at the ViewModel level, for example the SaveData command of the ViewModel does not run if any property of the ViewModel does not pass the validation.
So regarding your question, I would say that if you are going to validate you can do it in the view, but I think it is repeating code and can implement something that you can reuse.
You do well to use a design pattern, in your case MVC, in my case I use MVVM because it not only allows to separate the logic of your application or to reuse your ViewModels in other platforms (for example a Xamarin app), but also do not repeat code, do not repeat the implementation of validations for each model.