3

我想过渡到反应式视图模型/模型。

到目前为止,我已经使用了 3 个场景:

  • “ValueA”:一次只能从一个视图模型访问模型值,并且只能通过视图模型更改值

    => 模型中的简单属性,PropertyChanged视图模型中的转发属性

  • “ValueB”:模型值从多个视图模型和/或其他来源的更改中访问

    => 模型中带有事件的属性,转发属性和从更改的事件到PropertyChanged视图模型中的转换

  • “ValueC”:仅在视图模型中使用的值

    => 模型中没有属性,属性由PropertyChanged视图模型中的自己的字段支持

这是我的“当前”方法:

class Model
{
    public string ValueA {get;set;}

    private string valueB;
    public event ValueBChangedEvent ValueBChanged;
    public string ValueB
    {
        get
        {
            return valueB;
        }
        set
        {
            valueB = value;
            ValueBChanged();
        }
    }
}

class ViewModel : INotifyPropertyChanged
{
    private Model model;

    public string ValueA
    {
        get 
        {
            return model.ValueA;
        }
        set
        {
            model.ValueA = value;
            OnPropertyChanged();
        }
    }

    ViewModel()
    {
        model.ValueBChanged += model_ValueBChanged;
    }

    private void model_ValueBChanged()
    {
        OnPropertyChanged("ValueB");
    }


    public string ValueB
    {
        get 
        {
            return model.ValueB;
        }
        set
        {
            model.ValueB = value;
            // no change notification since done via model
        }
    }   


    private string valueC;
    public string ValueC
    {
        get 
        {
            return valueC;
        }
        set
        {
            valueC = value;
            OnPropertyChanged();
        }
    }       
}

这就是我打算使用响应式扩展对它们进行建模的方式:

class ReactiveModel
{
    public string ValueA {get;set;}

    private ISubject<string> valueB = new Subject<string>();
    public ISubject<string> ValueB
    {
        get
        {
            return valueB;
        }
    }
}

class ReactiveViewModel : INotifyPropertyChanged
{
    private ReactiveModel model;

    public string ValueA
    {
        get 
        {
            return ???;
        }
        set
        {
            ???
        }
    }


    private ReactiveProperty<string> valueB = model.valueB.ToReactiveProperty();
    public Reactive<string> ValueB
    {
        get 
        {
            return valueB;
        }
        // no setter since access via ValueB.Value which is read-write
    }   


    private ISubject<string> _valueC = new Subject<string>();
    private ReactiveProperty<string> valueC = _valueC.ToReactiveProperty();
    public ReactiveProperty<string> ValueC
    {
        get 
        {
            return valueC;
        }
        // no setter since access via ValueC.Value which is read-write
    }       
}

概括:

  • “ValueA”:我对这个案子一无所知
  • “ValueB”:乍一看有效,但既不会将更改从视图模型传播到模型,也不会以其他方式传播。
  • “ValueC”:按预期工作

如果我有 ValueA 和 ValueB 的解决方案,我会很高兴。

4

3 回答 3

2

ValueB:视图模型负责更新模型。ReactiveProperty仅使用模型属性中的 IObservable 接口并从中读取值ValueB(不写入任何内容)。 ReactiveProperty通过Value属性的视图改变。 ReactiveProperty实现IObservable,您应该订阅更改以获取新值。

ValueA:我们可以ReactiveProperty在视图模型端进行订阅,以将更改的值传播到模型。

这是解决方案的代码:

class ReactiveModel
{
    public string ValueA {get;set;}
    private readonly Subject<string> valueB = new Subject<string>();
    public IObservable<string> ValueB
    {
        get
        {
            return valueB;
        }
    }

    public void UpdateB(string newValue)
    {
        valueB.OnNext(newValue);
    }
}

class ReactiveViewModel
{
    private readonly ReactiveModel model;
    private readonly ReactiveProperty<string> valueA;
    private readonly ReactiveProperty<string> valueB;

    public ReactiveViewModel(ReactiveModel model)
    {
        this.model = model;

        valueA = new ReactiveProperty<string>(model.ValueA);
        valueA.Subscribe(x => model.ValueA = x);

        valueB = model.ValueB.ToReactiveProperty();
        valueB.Subscribe(model.UpdateB);
    }

    public IObservable<string> ValueA
    {
        get
        {
            return valueA;
        }
    }

    public ReactiveProperty<string> ValueB
    {
        get 
        {
            return valueB;
        }
    }
}

XAML 将在这两种情况下:

<TextBox Text="{Binding ValueA.Value, UpdateSourceTrigger=PropertyChanged}"/>
于 2015-11-28T20:27:09.413 回答
0

这是一个有争议的话题,但我个人并不认为属性更改通知是特定于视图模型和视图的,因此我使用 B,但我也在我的数据层中将 INPC 添加到模型中。这可以在使用 Fody 的后处理构建步骤中完成,也可以通过使用 Castle Dynamic Proxy 之类的东西将模型包装在代理中来完成。我个人使用后者,尽管它需要与您的 ORM 集成以免影响性能,即您不希望数据库代码加载模型对象然后认为该对象已更改,因为您尝试使用代理对其进行更新包装器(当您将 IList<> 转换为 ObservableCollection 时尤其如此)。

于 2015-11-23T23:26:20.727 回答
-2

您当前的方法似乎没有多大意义。您正在实现事件Model以在更改时发出信号,以便View Model可以采取行动。然而只有 View Model 应该改变 Model,因此事件是完全没有必要的。

View Model负责对 进行更改,Model因此它应该知道何时执行了更改,因为它是所述更改的来源。


纯粹的MVVM 方法是这样的:

public class MyModel
{
    public string MyValue { get; set; }

    ...
}

public class MyViewModel
{
    private MyModel _Model;

    public string MyModelValue
    {
        get { return _Model.MyValue; }
        set 
        {
            _Model.MyValue = value;
            //Notify property changed.
        }
    }

    ...
}

Model通知更改不是View的责任,而是通知ViewModel这些更改的责任。Model应该暴露给,而是应该暴露需要的的属性。ViewModelView

这样想吧。

  • 用户更改上的 a中的MyModelValue属性。TextBoxView
  • View通知ViewModel更改。
  • ViewModel变化Model

的唯一目的INotifyPropertyChanged是当上述过程相反时,ViewModel需要告诉View属性已更改:

  • 中的一个方法ViewModel称为更新MyModelValue
  • ViewModel通知View更改。
  • View更新TextBox. _

并不总是遵循视图所需的暴露属性的模式,相反,您可能会看到整个暴露于,但正如我之前多次说过的,MVVM 是一种模式,而不是法律。在中实施是完全可以接受的。Model ModelViewINotifyPropertyChangedModel

于 2015-11-25T08:52:24.697 回答