Search code examples
wpfmvvmmodelviewmodelcomposition

How to update a string property in the Model from an aggregated ViewModel


I'm working on a GUI application in WPF/MVVM. Let's say i have a Model class which is populated deserializing a (third-party) XML file

class Person
{
    public string Name { get; set; }
    public string Address { get; set; }
    public string ReservationId { get; set; }
}

and a ViewModel which exposes to its View a lot of properties and commands to manipulate the Model, in this case strings (such as ReservationId):

class StringManipulatorViewModel
{
    string modelString; //here's the problem

    public StringManipulatorViewModel(string modelString) 
    {
        this.modelString = modelString;
    }

    //Stuff to let the view manipulate the string
}

StringManipulatorViewModel is highly reusable and it is used by a lot of ViewModels, e.g.

class PersonViewModel
{
    Person model;
    public StringManipulatorViewModel ReservationManipulatorVM; //aggregated ViewModel
    public StringManipulatorViewModel AddressManipulatorVM; //aggregated ViewModel

    public PersonViewModel(Person model)
    {
        this.model = model;
        ReservationManipulatorVM = new StringManipulatorViewModel(model.ReservationId); //here's the problem
        AddressManipulatorVM = new StringManipulatorViewModel(model.Address); //here's the problem
    }
}

Obviously passing the string as "model" to the ViewModel isn't effective, and C# doesn't seem to allow string references as fields. What is the best/right way to let member ViewModels manipulate the Model when dealing with string types?

Thank you


Solution

  • Your problem is that you are trying to reference a property, not a string field.

    But you can pass a delegate to the setter of the property.

    If you also change the modelString field to a property, you can call this delegate automatically when the string is changed.

    class StringManipulatorViewModel
    {
        private string modelString
        {
            get { return _modelString; }
            set { _modelString = value; if (SetModelString != null) SetModelString(value); }
        }
        private string _modelString;
        Action<string> SetModelString;
    
        public StringManipulatorViewModel(string initialValue, Action<string> setModelString)
        {
            this.modelString = initialValue;
            SetModelString = setModelString;
        }
        //Stuff to let the view manipulate the string
    }
    

    You initiate the StringManipulatorViewModel in PersonViewModel like this:

            ReservationManipulatorVM = new StringManipulatorViewModel(model.ReservationId, value => model.ReservationId = value); //here's the problem
    

    Here are some other ideas when you want to pass a property.

    Passing properties by reference in C#