Should the MVVM ViewModel perform type conversion/validation?

后端 未结 5 1006
闹比i
闹比i 2021-01-31 08:19

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

相关标签:
5条回答
  • 2021-01-31 08:56

    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).

    0 讨论(0)
  • 2021-01-31 08:57

    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.

    0 讨论(0)
  • 2021-01-31 08:58

    Or should ViewModel properties expose the actual data types, leaving such chores to the view to handle?

    1. 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.

    2. 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.

    0 讨论(0)
  • 2021-01-31 09:09

    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.

    0 讨论(0)
  • 2021-01-31 09:09

    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

    0 讨论(0)
提交回复
热议问题