3

In MVVM-Light, the ViewModelBase class has a Set method:

protected bool Set<T>(ref T field, T newValue = default(T), bool broadcast = false, [CallerMemberName] string propertyName = null);

The goal of that method is to encapsulate various side effects that you might want to occur as a result of setting a property (property change notification, messaging, etc).

I want to expose the properties of my Model via properties in the ViewModel by delegating to the Model's getter/setter. E.g., for the Student (model), I am currently implementing the Student.Name wrapper in the ViewModel like this:

public class ViewModelBaseWrapped<T> : ViewModelBase where T: DomainObject {
    public ViewModelBaseWrapped(T wrapped) {
        m_wrappedDomainObject = wrapped;
    }

    private T m_wrappedDomainObject;
    protected T Wrapped { get { return m_wrappedDomainObject; } }
}

public class StudentViewModel : ViewModelBaseWrapped<Student> {
    public StudentViewModel(Student wrapped) : base(wrapped) { }
    public string FirstName {
        get { return Wrapped.FirstName; }
        set { Wrapped.FirstName = value;  }
    }
}

However, I would prefer to use ViewModelBase's Set function as so, to get access to the additional encapsulated functionality:

public class StudentViewModel : ViewModelBaseWrapped<Student> {
    public StudentViewModel(Student wrapped) : base(wrapped) { }
    public string FirstName {
        get { return Wrapped.FirstName; }
        set { Set(ref Wrapped.FirstName, value);  }
    }
}

That is illegal, however, because you can't pass a property of an object by ref. Can anyone think of a way to use the Set architecture while still being able to defer to the Model for use as the backing store?

David Cater
  • 415
  • 3
  • 15
  • That is a lot of overhead to your ViewModel. Why not to let the View read/write your Model properties? – E-Bat May 26 '15 at 15:55
  • Good point, and that's apparently a well-documented debate: http://stackoverflow.com/questions/1114555/a-view-model-mvvm-design-issue The short answer is that I want to maintain the ability to inject other functionality into the property getter/setter process, such as logging, undo/redo, etc. that I wouldn't want in the model. I could start by binding the View directly to the Model, but then if I wanted to alter the architecture later to support that sort of feature injection I would likely run into a situation where a large number of Xaml bindings would need to be visited and updated. – David Cater May 26 '15 at 16:19
  • mmm that post is a little old by now, I would not let requirements like logging etc, drive my design. With your current approach, basically you are moving the problem from Views to ViewModels. – E-Bat May 26 '15 at 21:33
  • Which problem are you referring to exactly? With the property wrapped in the ViewModel, the code is obviously more verbose; but now I have the overall linkages setup to add functionality later if I want to. So if the "problem" is inability to inject functionality, I think that problem is solved. If you're talking about maintenance headaches when the Model's properties change (forcing me to keep the ViewModel in sync), you're right. But once the problem is in the ViewModel it is a) more likely to be caught at compile time, and b) testable with unit testing (unlike the Views). – David Cater May 26 '15 at 23:24
  • 1
    That being said, I'm still wrestling with it. I have zero desire to blindly implement a useless layer that mimics the layer underneath it. Still, right now I do see more advantages than disadvantages. We'll see. And I would still like to figure out an elegant solution for the original problem I described. – David Cater May 26 '15 at 23:46

0 Answers0