简体   繁体   中英

MVVM - Who is responsible for

I'm a little bit confused at the moment because I'm not sure about things like "who is responsible for validating model data".

To give it an example:

I've got an application in which a relationship between a Person and specific devices gets visualized.

public class Person{
    public string Firstname {get; set;}
    public string Lastname {get; set;}
    public SomeSortOfDevice SomeSortOfDevice {get; set;}
}

public class SomeSortOfDevice{
    public DateTime DeviceExpiration {get; set;}
    public string DeviceSerialCode {get; set;}
    //public bool IsSerialCodeValid{get{
    //     SomeValidationLogic()
    //}
}

In the View the App-User can change the data of the Device. Now there are some Rules - for example the DeviceExpiration is bound to a TextBox but should only be Enabled if a valid SerialCode is set.

But who decides if the SerialCode is valid? The model itself? The ViewModel? Should the Model hold an extra Property "IsSerialValid" or how could the IsEnabled Property of a TextBox be bound to that rule?

Edit 1

public class ViewModel{
    public Person SelectedPerson {get; set;}
}

Thats how I'd use the Models above - The View will get some bindings on the SeletedPerson.

Edit 2

I think it's a litte bit more complicaten than I explained it before. Let's assume the Device is a Token and I want to determine if the User has entered something - if he entered something, is it valid?

If the validation should be handled in Model (as I've got it at the moment) the Model would look like this:

public Token{
    public DateTime ExpirationDate {get; set;}
    public string Serial {get; set;}
    public bool IsTokenExpired{
        get{
            return ExpirationDate.Date < DateTime.Now;
        }
    }
    public bool IsTokenValid{
        get{
            return new Regex("[0-9]{8,12}").Match().Success;
        }
    }
    public bool IsTokenSet{
        get{
            return TokenSerial.Length > 0;
        }
    }
}

Now to Enable the TextBox where the User should Enter (or select) a Date the Binding looks like this:

<TextBox IsEnabled="{Binding SelectedPerson.Token.IsTokenValid}"/>

This works just fine but I don't really have got a good feeling about the validation rules inside the Model.

Well, this is just an opinion,but this is how i would do it.

First, your model should have a validation method, something like public bool ValidateSerial(string serial);

Then, in your ViewModel you'll have a property binded to the TextBox and you'll do the check there,something like:

_private string _serialNumber;
public string SerialNumber
{
    get
    {
         return this._serialNumber;
    }
    set
    {
         this._serialNumber=value;
         RaisePropertyChanged("SerialNumber");
         this.IsSerialValid=Model.ValidateSerial(string serial);
         RaisePropertyChanged("IsSerialValid");
    }
    public bool IsSerialValid { get; set;}
}

The IsSerialValid property is the one you'll bind to the IsEnabled property of the other TextBox.

Hope this make sense to you.

I think it all depends on the specific design. In general, you can implement some logic checks in the model, but the model should not (and cannot) communicate with UI. So typically the model would just refuse to store the data if something is wrong.

The visibility of controls should be handled in ViewModel, as you correctly suggested in your code. However, in your case when someone enters incorrect serial code, the IsValid property would not be changed (since in is calculated on demand). The better way would be to check the Serial Code in the setter of DeviceSerialCode, and set the IsSerialCodeValid from there. In order for the UI to reflect the change, your ViewModel should also implement INotifyPropertyChanged interface, and signal changes to the properties in their setters.

No need to hold an extra property. Just implement the interface INotifyPropertyChanged which emits an event when the property value changes.

You can listen to the property's property changed event in the view model and do the checking there. This is how the view also gets updated in an MVVM model.

You can also bind the textbox's IsEnabled property to a viewmodel property which is set during the check if it contains a valid value.

If you want, you can also use a converter for the IsEnabled property and pass the text as Command Parameter, so that the converter checks the text and sets the bool value of IsEnabled property of textbox as required.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM