Is there a best practice or widely accepted way of structuring and validating data using MVVM in conjunction with RIA services in Silverlight?
Here’s the crux of my problem. Let’s say I have an EmployeeView, EmployeeViewModel and some Employee entity. In regular RIA applications I will expose that Employee entity on the view and I get validation “for free”, because Entities implement INotifyDataErrorInfo and IDataErrorInfo (correct?).
Now if I want to expose some Employee properties through a ViewModel instead of directly through an Entity then it becomes more complicated. I could expose the bits that I need directly and hook them into the entity on the backend, like this:
private Employee _employee;
public EmployeeViewModel()
{
_employee = new Employee();
}
public string Name
{
get { return _employee.Name; }
set
{
_employee.Name = value;
// fire property change, etc.
}
}
… but I lose the tasty “free” validation of entities. Otherwise, I could expose the entity directly in the view model, like so
private Employee _employee;
public Employee Employee
{
get { return _employee; }
}
public EmployeeViewModel()
{
_employee = new Employee();
}
In this case, the view will bind directly to the Employee entity and find its properties in there, like so:
<StackPanel DataContext="{Binding Employee}">
<TextBox Text="{Binding Name}" />
</StackPanel>
Using this method we get “free” validation, but it’s not exactly a clean implementation of MVVM.
A third option would be to implement INotifyDataErrorInfo and IDataErrorInfo myself in the VMs, but this seems like an awful lot of plumbing code, considering how easy it would be for me to use the above solution and have something slightly less “clean” but a heck of a lot easier at the end of the day.
So I guess my question is, which of these approaches are appropriate in which situation? Is there a better approach I am missing?
In case it’s relevant I’m looking at the Caliburn.Micro MVVM framework, but I would be keen to see answers that apply generically.
I am using RIA with Caliburn.Micro and am pretty happy with my solution for client side validation.
What I have done is put a
ValidationBaseViewModelbetweenScreen(provided by Caliburn.Micro) and my actual application VMs (EmployeeViewModelin your case).ValidationBaseViewModelimplementsINotifyDataErrorInfoso that plumbing code your talking about is only written once. I then add/remove/notify of errors viaValidationBaseViewModelfrom an override of the (Caliburn.Micro)PropertyChangedBase.NotifyOfPropertyChangewith the following code:This is actually in another VM (between ValidationBaseViewModel and EmployeeViewModel) with the following definition:
where
Entityis RIAsSystem.ServiceModel.DomainServices.Client.Entityand the_editingclass member is an instance of this typeTEditwhich is being edited by the current VM.In combination with Caliburn coroutines this allows me to do some cool stuff like the following: