简体   繁体   中英

MVVM Light ViewModelBase vs Encapsulation

I've been using MVVM Light for a while now - it's extremely useful and almost always the first library I add to a new project!

I'm wondering what the implications would be of developing a class that implements INotifyPropertyChanged to encapsulate a bindable property (example below).

public class BindableProperty<T> : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;


    private T mValue;
    public T Value
    {
        get { return mValue; }
        set
        {
            if (!EqualityComparer<T>.Default.Equals(mValue, value))
            {
                mValue = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("Value"));
                }
            }
        }
    }


    public BindableProperty(T default_value)
    {
        mValue = default_value;
    }
}

With this class, I have to change my Xaml, but I believe my ViewModel might be more readable (below) - especially when the number of properties grows.

<TextBox Text="{Binding FirstName.Value, UpdateSourceTrigger=PropertyChanged}"/>

public class MainVM
{
    public BindableProperty<string> FirstName { get; private set; }
    public BindableProperty<string> LastName { get; private set; }

    public MainVM()
    {
        FirstName = new BindableProperty<string>("");
        LastName = new BindableProperty<string>("");
    }
}

I know MVVM Light is designed to be extremely flexible, lightweight, and provide complete control (which it does very well). I can of course combine implementations and use the BindableProperty class above for some properties and more explicit ViewModelBase code for other properties in more complex situations.

Am I missing something obvious? What are some of the trade offs for this design that I might not be aware of (eg implications of changing xaml binding, data validation...)?

There is no extra value in encapsulating a property. This may work for very simple scenarios, but as soon as your ViewModel becomes more complex, you'll end up wiring your encapsulated classes in odd ways.

This approach won't work very well with validation neither it will if you have properties that depend on each other, ie FirstName , LastName and FullName where FullName is just a public string FullName { get { return FirstName+" "+LastName; } } public string FullName { get { return FirstName+" "+LastName; } } .

Same applies for validation (with IDataErrorInfo ). With the base class your code looks like

public string FirstName 
{
    get { return firstName; }
    set
    {
        if(string.IsNullOrEmpty(value)) 
        {
             // where errors is a Dictionary<string, string>
             errors.Add(nameof(FirstName), "First name can't be empty.");
             return;
        }

        if(value.Length <2) 
        {
             errors.Add(nameof(FirstName), "First name must be at least 2 characters long.");
             return
        }

        Set(ref firstName, value);
        errors.Remove(nameof(FirstName));
    }
}

This will be a pain to implement in encapsulated properties

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