I'm converting one of my existing applications to the MVVM pattern to improve its structure and I'm a bit torn on what would be the best way to do the data validation.
Currently the application uses data binding to link the UI and code and uses a few validation rules and value converters which can be reused on similar values (one of each for dates, etc.).
Whilst reading up on MVVM I've come across IDataErrorInfo, which I find attractive because it would keep validation out of the view, thus slightly reducing repetitive code when setting bindings, etc. and allow for more specific error messages.
ValidationRules on the other hand block the transfer of binding data if the validation fails, which I need because I only want the model values to change a new, valid value is supplied.
My major concern is that if I restrict things too much in the viewmodel that this will make things difficult in the view - is it a good idea to restrict things to a comfortable level in the general case and then remedy specific cases that need more flexibility in the view?
So my main question is, would it be better to put validation and conversion in the properties of the viewmodel or stick with my validationrules and valueconverters (or some compromise in between)?
I implement all validation in the view model, using IDataErrorInfo, and let the view model decide whether or not it should pass property changes to the model based on whether the property is valid. So a typical setter looks something like:
public string Value
{
set
{
if (value == _Value)
{
return;
}
_Value = value;
Validate("Value");
if (Error["Value"] == null)
{
Model.Value = value;
}
OnPropertyChanged("Value");
}
}
I never, ever implement validation or value conversion in the view. That just seems like begging for trouble.
I would use a combination.
I use Idataerrorinfo in my entities (validation is not in the viewmodel) for core re-usable business rules. My entities can also validate themselves this way.
I then use view ValidationRules for places where a binding error will not make it to my entity such as when a string is used as input in a integer textbox.
Related
Trying to figure out how to capture view-only validation errors such as entering non-numeric characters in a text box bound to an integer property. I would like the Catel DataWindow to behave consistently.
Description:
I have a Catel MVVM window (implemented using DataWindow and a view model with a model property.)
The model property is an integer:
public Foo { get { GetValue .......... } }
The view model property is also an integer, and bound to the model:
[ViewModelToModel(...)]
public Foo { get { GetValue .......... } }
In the view, there is a text box that is bound to Foo. When the user enters a non-integer value in the text box, there is naturally an error in the binding process, and because the text box has ValidatesOnExceptions set to true, the following appears in the Catel info message bar:
Two problems that I must fix:
I need a custom error message ("Value 117.228 could not be converted" is not going to fly here.)
The WarningAndErrorValidator does pick up the error, but the DataWindow OK button is still enabled, and I am able to "save" the view model. I need OK to be disabled when there are any errors, even if they don't make it to the view model.
A web search has provided a couple possible solutions:
Bind to a view model property that's a string, and handle mapping/conversion between the view model and the model
Build support in the MVVM framework to trap UI validation errors and communicate them to the view model
Solution #1 is definitely the "workaround" solution because it means I need something like this in the view model (excuse the pseudo-code...):
[ViewToViewModel(...)]
public int Foo { ...... }
// Also a Catel property
public string Foo_Raw { ...... }
// Property changed handlers for both the above properties, keeping them in sync with one another when possible...
protected override void ValidateBusinessRules(List<.......> validationResults)
{
if (this.Foo_Raw != this.Foo.ToString())
{
validationResults.AddError("Foo must be an integer.");
}
}
I am not pleased at the prospect of creating this kind of rickety structure.
I'd much rather go with something like #2, but I didn't see anything in Catel's documentation that suggests that approach is supported. Did I miss an easy solution?
UPDATE: I just learned about the numeric text box behavior which might be another way to solve my specific problem, but I am really looking for a more general solution for capturing binding/UI errors in the view model validation.
The issue is that the exceptions you are trying to receive are not yet bound (since binding them goes wrong). There is no way for the vm to be aware of this issue. Since this is a view-related issue, you can only handle this error in the view.
One solution might be to forward the messages caught by the WarningAndErrorValidator onto the view model. You can define your own WarningAndErrorValidator on the view and subscribe to the Validated event. Then you can pass this onto your vm. This will require you to write a custom base class for your views if you want this shared among all controls in your app.
Geert van Horrik's answer was not quite correct (unless I missed something, Geert). The WarningAndErrorValidator only traps view model errors, not errors from the visual tree itself, or binding errors. It turns out that is something the InfoBarMessageControl does without help from the WarningAndErrorValidator.
What I did was, in my subclass of DataWindow, I duplicated the logic from InfoBarMessageControl that traps and analyzes visual tree validation errors, and I maintained a similar error message data structure.
I then overrode DataWindow::ValidateData like so:
protected override bool ValidateData()
{
// In addition to base class logic, make sure there are no errors of any kind including view-only errors (like binding exceptions or ValidationRule errors).
return base.ValidateData() && this.ViewErrorCount == 0;
}
ViewErrorCount is a simple int that I update when I trap errors as described above.
I known there are several existing questions about whether to implement INPC on the model, most arguments are about code repetition because of property proxies, which will be not a concern in this case, because the Model and the ViewModel will be autogenerated by a tool, so any code-size arguments is invalid.
There are any drawbacks in not implementing INotifyPropertyChanged on the Model besides code size?
Also, the generated Model will be used directly by the programmers but the ViewModel will only be used by other generated code, so the size and complexity of the view model will be hidden, but the Model has to be as simple as possible without losing functionality, in this case Is better to implement validation and calculated properties on the model or in the view model?
Consider that the model may be or not database entities.
Thanks
This is too generic a question to be answered.
"Is better to implement ... ?" : This depends on the application need . Ideally the Model has all the properties and the Viewmodel is just the place where you fill the Model and write the necessary business logic.
Since you are talking about autogeneration, i suppose you have written some util which does this creation. Ideally the validation should be present in both Model and ViewModel. Model side validations are supposed to check any DB/server side validation if present and the ViewModel(VM) is supposed to validate the client for eg: In VM you validate for whether a property is greater than some other property, but in the Model validation you would validate for uniqness or null etc.
Other thing is the calculated properties(I hope this means calculation done in the database and filled in a property), these properties ideally should reside on the ViewModel .
Hope this answers your question.
In my project I have a model and I want to bind the visible state of a label using one of the model properties. I do not want to add another ShowLabel property to the model. I want to be able to write something like this:
label.Bindings.Add("Visible", model, m => m.Name != "Default");
Basically I want to be able to write a lambda expression instead of adding a property to my model. Is this possible?
Yes, you can do this using the Format event of the Binding class. You'll still bind to the property in question, but your Format event handler will return a different value (a bool in this case).
var binding = new Binding("Visible", model, "Name");
binding.Format += (sender, args) => args.Value = (string)args.Value != "Default";
label.DataBindings.Add(binding);
Windows Forms data binding recognizes the ICustomTypeDescriptor interface, which allows an object to decide at runtime which properties it presents to data binding. So if you write an implementation of that, you can tell Windows Forms that you have whatever properties you feel like having, and you can decide how to implement them.
Of course, that may not help - if you wanted to avoid adding a property, you may also want to avoid implementing a fairly complex interface. The obvious solution would be to write a type whose job is to act as the data source and bind to that instead of whichever object you're currently binding to.
Of course, if you do that it's probably then easier just to implement whatever property you were going to implement on that wrapper instead.
In general with databinding, you want to avoid binding directly to some underlying model, precisely because you don't want to have to add things to your model purely for the benefit of the UI. This is why 'separated presentation' is very popular - instead of connecting the model and view directly, you stick something in the middle whose job is to mediate. Some call this a viewmodel, some call it a presenter, but the basic principle is always separation of presentation.
It sounds like you're trying to achieve separate of presentation (which is good) but without introducing an extra type so that this middle layer has somewhere to go. Why not just define a class (or a set of classes) to act as that layer?
We're just getting into MVVM in WPF.
We have implemented our ViewModels with 'strongly typed' properties (int, double? etc.) that we bind to in the view.
Type conversion works OK, mostly, and so entering data is simple enough. But we run into problems with validation.
If, say, a non-numeric value is entered in a text box bound to a numeric property, the conversion fails, the property is never set, and we never get a chance to provide proper feedback to the user. Worse, the property retains its current value, leading to a mismatch between what's displayed in the view and what's actually in the ViewModel.
All this can be handled with value converters, I know. But I have seen several opinions to the effect that conversion should not be the view's responsibility at all. What is entered in the view are strings, and the conversion, validation etc. should be the ViewModel's responsibility (so the argument goes).
If so, we should rewrite most of the properties on our ViewModels to string, and provide error information through the IErrorInfo interface, for example. It would surely make for simpler, leaner XAML in the view. On the other hand, conversion, validation etc. will be less declarative, explicit and flexible, from the point of view of the View designer.
It seems to us these two approaches are fundamentally different, so before we decide, we'd like some informed SO opinions on the matter.
So: should ViewModels expose a simplified, 'text-based' interface to the view and handle conversion internally? Or should ViewModel properties expose the actual data types, leaving such chores to the view to handle?
Update:
Hard to pick a winner here, but I finally landed on one of you who concludes more or less like myself.
Specifically, we have decided to keep the ViewModel properties typed. The main reason for this is the flexibility it affords us in the design of the view, and the power of explicit, declarative conversion/formatting in XAML.
I noticed an assumption with you who will disagree with us in this, that the design of the view is fixed and ready. Hence, no decisions about conversion, formatting etc. need be made in the view. But ours is an agile process, and we haven't got all the nitty gritty detail of the UI figured out on beforehand.
In fact, leaving the details of the UI to be worked out along the way leaves room for creativity and besides, in my opinion, even a meticulously worked out design will always end up morphing throughout the implementation process.
The point of all this is that whereas business rules enforcement certainly belongs in the ViewModel, it seems to us that simple conversion and formatting is a view-thing. It may sound like heresy, but I don't actually think type conversion in the view needs unit testing at all (so long av we unit test the actual type converters).
All in all a great discussion, folks, with well formulated, informed opinions. Thanks.
This is a very interesting question and one that I don't feel has a definitive answer, but I'll do my best to throw my thoughts out there.
Looking at the MVVM pattern as I understand it, the point of the ViewModel is to expose the data in a way the View can understand without any assumptions about the way the view is going to use it. For an example let's pretend that we are modelling the speed of a car:
public class CarModel
{
public int MilesPerHour { get; set; }
}
public class CarViewModel
{
private CarModel _model;
public int MilesPerHour
{
get { return _model.MilesPerHour; }
set { _model.MilesPerHour = value; }
}
}
In the example above I've exposed the property as an int since that is what it is in the model. The disadvantages of this you have listed in your question, but the main advantage is that it gives the creator of the view a valuable piece of information about how to display that data. Remember that we (as the authors of the ViewModel) don't know what the View looks like. By committing to the idea of the data being an int the View can use a textbox or some other control that only accepts numbers (a dial, for example) to display the information. If we say that we are going to format the data in a way that we assume is helpful to the View it takes that important power away from it.
On the other hand we work in real world. We tend to know what the view is. We rarely plug and play different views on top of the same ViewModel and adding the conversion code into the ViewModel is simply easier. I don't think it is right, but that doesn't mean you won't find my production code using it...
Finally (and I'm sure you know this, but for completions sake...) business logic should be done in the ViewModel. If we decide that the car shouldn't go above 70mph then it isn't the responsibility of the view to enforce that. So you'll still end up with some kind of error provider, but at a business rather than display level.
Okay, maybe that wasn't finally....
I wanted to address the comments made by Kent, and my thoughts didn't fit into a comment.
Obviously the primary difference between my and Kent's point of view (as I understand it) is he reads ViewModel to be a Model of the View and I read it to be the thing that exposes the Model to the View. A subtle difference I'll admit, but I think the upshot is that I don't want to remove information that the model provides, even if it makes it easier for the specific view I'm using.
My point of view is based on the assumption that you should be able to swap views out, they should be fleeting things that may change depending on the requirements of screen size, hardware, platform, latency and environment. The interesting twist is that I have never actually needed this functionality, nor seen anything (beyond proof of concept applications) that have ever used it, but if we accept that we won't use it now or at any point in the future, and that each ViewModel will work with one, and only one, View then we may as well go back to putting all the code in the code-behind file and throw the ViewModel out completely - after all, it's so tightly coupled that it may as well be the same class.
Ideally I would like a situation where the ViewModel can say "this value is an int, it will always be an int, and you can display it in anyway that you like. But you can give anything back to me and I'll do my best to make it fit, and if I can't I'll let you know". Basically my MilesPerHour property should have an int getter, but an object setter. That way the views keep all the information I feel they need, but don't have to worry about conversions or validation.
Absolutely it belongs in the view model, for all the usual reasons, including:
Designers own the XAML. Do you want the designers to have to understand and implement the requisite type conversion and validation logic?
Testability. Don't you want to validate that your conversion and validation logic is working correctly? It's much harder if it's embedded in the view.
On the other hand, conversion, validation etc. will be less declarative, explicit and flexible, from the point of view of the View designer
I think this is a moot point because the view designer should be responsible for these things. The designer is trying to make the UI look and feel a certain way; it is the developer who implements the business logic, including conversion and validation logic.
Should the MVVM ViewModel perform type
conversion/validation?
Yes.
The view model is an abstraction layer between the view and the model - the perfect spot to perform any type conversions (instead of cumbersome value converters). Validation should absolutely occur as part of the view model.
We use our View Model to handle the conversions as much as possible for data types. This reduces the need for a value converter to some very specific circumstances. You want to expose whatever type is easiest for the view to consume. This has been working well.
The one specific question you raised:
If, say, a non-numeric value is
entered in a text box bound to a
numeric property, the conversion
fails, the property is never set, and
we never get a chance to provide
proper feedback to the user. Worse,
the property retains its current
value, leading to a mismatch between
what's displayed in the view and
what's actually in the ViewModel.
might be handled by exposing your view model type as a nullable type. This should still allow the underlying source to be updated, even if invalid data is entered, and trigger validation. This worked in a similar situation we had with DateTime and a date time picker.
Keep the view as dumb. We don't have official designers, our developers are our designers, so keeping the view dumb has some benefits:
We (developers) get to keep our sanity (XAML is somewhat less verbose)
Business logic (including validation) stays in the view model and can enable testing
Good Luck!
-Z
This is a good question, and I can certainly see both sides of the discussion.
My thought is that what you're really looking for is a proper NumericInputControl that you can use in your xaml. This will provide a better user experience because your users won't be able to accidentally enter text in a number field and, because the control constrains input without validating it, you can maintain the more strongly-typed ViewModel.
I'm not sure how you'd want to go about implementing one, I know that the classic spinner/NumericUpDown controls are falling out of favor because they aren't touch-friendly, but I don't believe that the introduction of such a control will violate the purity of the design approach or your ViewModels. You'll receive a number that you can then range-validate in the appropriate place, supply feedback via IDataErrorInfo as usual, and so forth. :) This technique lets you get the best of both worlds without any real drawbacks (except the creation of a numeric control).
Or should ViewModel properties expose the actual data types, leaving such chores to the view to handle?
Conversion and templates are done in View, because they both are just a conversion of values, models and viewmodels into controls! Controls are available only inside View.
Validation is done in ViewModel, because validation is done according to business rules and can even be done through a call to a remote service. View knows nothing about business rules, but knows how to present validation results.
If, say, a non-numeric value is entered in a text box bound to a numeric property
A properly crafted numeric text box control never allows user to input a non-numeric value.
as far as I understand the ViewModel should abstract the model from the view and add additional logic to handle the presentation stuff.
My question is:
How would I create a dataform that is suppose to handle user input for an order and details at once.
It should present fields for entering the orders as well as the fields for 1 detail.
My Model would have an object for an order which contains a list of OrderDetails.
How would look my ViewModel for my OrderEntryForm like?
Would I have an OrderViewModel and an OrderDetailViewModel and my
my OrderEntryForm would contain a property of OrderViewModel and one for OrderDetailViewModel? (nesting ViewModels?)
How would validation be handled in this case? Since Validation should go close to the model?
Especially when I work with RIA-Service...
Wouldn't it make more sense to put it in the ViewModel?
How far would you abstract the Model from the ViewModel?
Example:
private DateTime _OrderDate;
public DateTime OrderDate
{
get { return _OrderDate; }
set
{
if (_OrderDate != value)
{
_OrderDate = value;
OnPropertyChanged("OrderDate");
}
}
}
this would mean I have to map the ViewModel-Property to Model-Properties. Cannot leverage Validation-Logic from the Model here...
This example:
public DateTime OrderDate
{
get { return Model.OrderDate; }
set
{
if (Model.OrderDate != value)
{
Model.OrderDate = value;
OnPropertyChanged("OrderDate");
}
}
}
would requiere to pass in a Model. Have the access to the validation logic of the model but also a coupling...
Most examples on the web show dataforms which use ViewModel's that a just a representation of the tables not a real abstraction...
I know and I saw this
stackoverflow.com/questions/744474/combining-net-ria-services-and-mvvm-in-silverlight-3-0
I also read nikhils blogpost on this but this handles also only Products straight mapping from the tables of the database... =(
I know alot of questions...
What are your opinions on that topic?
How would you handle complex dataforms?
Chris,
I have had the same issue and end up implementing it in a crappy way :-( (two vieModels one per view, but passing the parent to the child View... bad stuff).
From my error I learn that next time I would give a try to:
Generate a single ViewModel, but in the child view pass a detail entity in the datacontext (this detail entity does not have to match with the proxy generated entities, maybe is a container of that entities).
Generate a singleton controller class: this class won't be exposed to the view, it will be transparent for the view, just the detail view model will ask the controller for that dependant data instead of going to the DAL.
Not sure if this are going to be clean solutions, have to give a try and fail :).
I agree with you... there are not real samples with this kind of scenarios.
What do you think?
Thanks
Braulio
PS: About validation, if we create our own super entities, we can there define our validation, in my case I have tried as well extending the entities using partial cases and then I can have an entity myPhoneNumberDetail with my special validation.
I personally think there are no hard and fast rules... well, there is one - be pragmatic.
Pragmatically speaking, a view model is a model, and so is a data model. Both are classes, independent of the UI, and surface state as properties, operations as methods, and notifications as events. The thing that I think in my mind differentiates them is how general they are. I see a model as generally usable across multiple views, vs. a view model optimized for a particular view.
I would personally never abstract for the sake of abstracting. I would never surface top-level properties for every model property and implement it by delegating to an underlying model. This increases work. It increases the amount of code to be tested. It requires propagation of metadata, change notifications etc. If there is some actual logic to add, then yes, there would be properties on the view model I'd expose and delegate to the underlying model as appropriate. Even there I'd ask if it is reasonable/appropriate to expose those as computed properties on the model (view model and data model are both models).
As far as surfacing DAL types directly vs. not, that in my mind is somewhat orthogonal. It depends on other factors - how much do you want to abstract the DAL, how useful a DAL type is - for example, if a DAL type has a lot of foreign keys, a presentation model equivalent or projection might be more useful where there is some denormalization done. Sometimes security might be the reason to write a presentation model/projection - eg. I don't want to send email addresses to the client, and instead want an alternate representation of email addresses.
In my sample, I used a DAL type directly, to simplify and not have an overload of concepts in a single sample. I do want to blog about presentation models and projections in a dedicated manner... and so didn't want to mix posts of viewmodel and .net ria services with presentation model concepts at the same time.
As is so often, with patterns, it really depends. The ViewModel can expose the underlying model, and there is no hard and fast rule that says you "must" hide everything and delegate. I have spoken to many folks that are strict adherents to LOD and still they agree that in the case of UI binding, it does not apply.
Now in the case of whether that model is a DTO or not there you will find a lot of differing opinions. Some believe that the only thing that should ever be on the client is a pure projection i.e. a DTO with all logic living on the server, while others believe that that moving entities between the tiers is fine. That would be an discussion for a different post. :-)
In general the guideline that i would recommend is always at least have a high-level VM which can be used for screen state, etc.
As far as child models, like OrderDetail, then if the child model is sufficent to just bind to then just expose it directly. Now one thing to consider is around notification, if you model is not implementing INPC than you may have no choice but to wrap it in order for binding to properly work.
Even if it implements INPC there may be view-specific concerns that that model does not contain, but which are required to for the view to function. In that case I would use simple aggregation and create an OrderDetailVM that directly exposes the underlying OrderDetail and adds additional properties.
For example
public class OrderDetailViewModel
{
public OrderDetail OrderDetail {get;set;}
public bool IsValid {get;set;}
}
Where IsValid is checking some screen-specific logic.
It really depends though on how much encapsulation you want to achieve. I wouldn't find anything wrong with using a delegation model. Depending on the complexity though it might get unwieldy, for example imagine if OrderDetail had additional children, etc.
HTH
Glenn
To clarify, the VM is an abstraction of the Model, not of the View and not the other way around.
You can certainly use multiple VMs to correspond to discrete portions of your View. If you're not going to need separate VMs for Order and Details, you can just have an OrderAndDetialsViewModel that contains everything, and the whole View will bind straight to that. This is where the abstraction comes in.
You are right, that your model's validation logic is going to be distinct from your ViewModel's validation logic, if you put any in there. In no case will the validation be in the View.
I'm not sure I follow your second example. What is the Model object? Your VM may know about the Model(s) from which it is composed, but it is not going to expose it/them as such directly to the View.
I hope this helps somewhat. Please let me know if there is any part of your post that I failed to address.