Reputation: 1857
I'm using RIA Services with LinqToEntitiesDomainService<> and Silverlight 5 Beta to generate the DomainContext code on the client side. I have Data Annotations in my Models/Entities to do basic validations, and when using the Models directly, controls such as DataForm perform validations out-of-the-box. But I'm wrapping my Model in a ViewModel, so I lose all of that automatic validation. Here is a simplified example:
// In DataModel assembly, regenerated on the client side by RIA Services
public class PetModel
{
[Required]
public string Name { get; set; }
}
// Only on the client side
public class PetViewmodel
{
private PetModel _model;
public PetViewmodel(PetModel model)
{
_model = model;
}
public string Name
{
get { return _model.Name; }
set { _model.Name = value; }
}
}
My question is: how can I ensure that Name
is considered Required
on the client side without duplicating all of my annotations in the ViewModel? (I may have to use these Entities with different ViewModels in the future - and I'd like to keep the same annotations)
I thought of manually adding the MetadataType
attribute to the ViewModel, pointing to the Model type:
[MetadataType(typeof(PetModel))]
public class PetViewmodel
{
...
}
But alas, MetadataTypeAttribute
is not available in the Silverlight 5 version of System.ComponentModel.DataAnnotations
.
Edit: Clarification - the metadata for my entities is included in the entities with a nested class. I code this class manually because my L2E model is in a separate assembly so the DomainService wizard would not generate it for me.
[MetadataType(typeof(Metadata))]
public partial class PetModel
{
[Required]
public string Name { get; set; }
public class Metadata
{
[Required]
public string Name { get; set; }
}
}
This should be exactly how the wizard would generate the metadata if I understand it correctly. The RIA Services code generator generates the right data annotations in the client code, so it's picking it up correctly.
Upvotes: 4
Views: 2416
Reputation: 1857
I found a way to do this. In hopes that it will help someone in the future:
I used a base class for the viewmodel that performs validations. On that base class I implement INotifyDataErrorInfo
, and I override the NotifyOfPropertyChange
method (This is part of Caliburn.Micro, but if you're not using you could just as easily attach to the PropertyChanged
event for the model). In the event handler, I perform validation on that property. In the validation code, I use reflection to find the property of the same name, and any validation attributes on the property (RequiredAttribute
, RangeAttribute
, etc). Then I use the values from these properties to validate the new value on the changed property, creating ValidationResult
objects and adding them to a List<ValidationResult>
. If all of the 'local' validations pass, then I proceed to perform 'remote' validations (i.e. Validations that require interaction with the server, such as checking for uniqueness).
It was a lot of work, but unfortunately this - or something similar - is necessary. All of the MS examples appear to not use the MVVM. I thought this was just to keep them short/simple, but the Silverlight team at MS appears not to have given serious consideration MVVM when designing the object model.
Upvotes: 1