如何从聚合的 ViewModel 更新模型中的字符串 属性

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

我正在 WPF/MVVM 开发 GUI 应用程序。假设我有一个模型 class,它反序列化了一个(第三方)XML 文件

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

和一个 ViewModel,它向其 View 公开许多属性和命令来操作 Model,在本例中为字符串(例如 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 是高度可重用的,它被很多 ViewModels 使用,例如

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
    }
}

显然将字符串作为“模型”传递给 ViewModel 是无效的,而且 C# 似乎不允许将字符串引用作为字段。 best/right 在处理字符串类型时让成员 ViewModels 操作模型的方法是什么?

谢谢

我想不出一种“正确”的方式来操作字符串作为 StringManipulatorViewModel 中的引用,一旦您将字符串作为值传递,它就与模型无关。

但是,每当 StringManipulatorViewModel 操作它时,合法更改 model 字符串值的方法是在视图模型操作字符串时在视图模型中引发 Event,然后添加使用新值更新模型的事件处理程序:

class StringManipulatorViewModel
{
    string modelString;

    public event EventHandler<string> StringManipulated;


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


    public ManipulateString() 
    {
        // Manipulate the string

        StringManipulated?.Invoke(this, modelString);
    }
    
}

并且在 PersonViewModel 构造函数中:

class PersonViewModel
{
    Person model;
    public StringManipulatorViewModel ReservationManipulatorVM;
    public StringManipulatorViewModel AddressManipulatorVM;

    public PersonViewModel(Person model)
    {
        this.model = model;
        ReservationManipulatorVM = new StringManipulatorViewModel(model.ReservationId); 
        AddressManipulatorVM = new StringManipulatorViewModel(model.Address);

        ReservationManipulatorVM.StringManipulated += (sender, e) => model.ReservationId = e;
        AddressManipulatorVM.StringManipulated += (sender, e) => model.Address = e;
    }
}

您的问题是您试图引用 属性,而不是字符串字段。

但是您可以将委托传递给 属性 的 setter。

如果您也将 modelString 字段更改为 属性,则可以在更改字符串时自动调用此委托。

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
}

您像这样在 PersonViewModel 中启动 StringManipulatorViewModel:

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

当你想传递 属性 时,这里有一些其他的想法。

Passing properties by reference in C#