定义视图是否加载或设置属性

时间:2017-01-05 09:11:25

标签: c# wpf mvvm catel dirty-data

我正在尝试用Catel制作一个“Dirty”实现。
我有一个viewmodel,其[Model]属性和一些[ViewModelToModel]映射到它 我添加了一个布尔成员_canGetDirty,当设置为true时,允许viewmodel属性提示服务进行保存。

所以我的逻辑是,如果模型属性发生更改,_canGetDirty将设置为false,因此viewmodel属性会更改而不会变脏,并且当模型完成更改时,我们设置{{1} } _canGetDirty重新开始。

问题是在更改viewmodel属性之前调用了model属性的true事件,因此PropertyChanged始终为true,并且每当我加载新模型时都会调用我的服务进行保存

如何解决此问题?

_canGetDirty

编辑:关于Catel如何在此背景下工作的一些解释。

注册属性更改:

我们注册的属性会通过public class MyViewModel : ViewModelBase { private IMyService _myService; private bool _canGetDirty; public MyViewModel(MyModel myModel, IMyService myService) { MyModel = myModel; _myService = myService; } [Model] public MyModel MyModel { get { return GetValue<MyModel>(MyModelProperty); } set { _canGetDirty = false; SetValue(MyModelProperty, value); } } [ViewModelToModel("MyModel")] public string Prop1 { get { return GetValue<string>(Prop1Property); } set { SetValue(Prop1Property, value); } } [ViewModelToModel("MyModel")] public string Prop2 { get { return GetValue<string>(Prop2Property); } set { SetValue(Prop2Property, value); } } [ViewModelToModel("MyModel")] public string Prop3Contains { get { return GetValue<string>(Prop3Property); } set { SetValue(Prop3Property, value); } } #region Registering public static readonly PropertyData Prop1Property = RegisterProperty("Prop1", typeof(string), null, PropertyToSaveChanged); public static readonly PropertyData Prop2Property = RegisterProperty("Prop2", typeof(string), null, PropertyToSaveChanged); public static readonly PropertyData Prop3Property = RegisterProperty("Prop3", typeof(string), null, PropertyToSaveChanged); public static readonly PropertyData MyModelProperty = RegisterProperty("MyModel", typeof(MyModel), null, MyModelChanged); #endregion #region Property Changed Handlers private static void MyModelChanged(object sender, PropertyChangedEventArgs e) { (sender as MyViewModel)._canGetDirty = true; } private static void PropertyToSaveChanged(object sender, PropertyChangedEventArgs e) { var vm = sender as MyViewModel; if (vm._canGetDirty) vm._myService.AskForSaving(); } #endregion } 通知更新:

RegisterProperty

最后一个参数是注册属性更改时调用的回调函数。

自动更新模型的属性:

我们将属性设置为模型:

public static readonly PropertyData Prop1Property = RegisterProperty("Prop1",
    typeof(string), null, PropertyToSaveChanged);

此类包含一些属性(Prop1,Prop2,Prop3)。 Catel允许我们通过使用ViewModelToModel映射它们来自viewmodel自动更新它们:

[Model]
public MyModel MyModel
{
    get { return GetValue<MyModel>(MyModelProperty); }
    set
    {
        _canGetDirty = false;
        SetValue(MyModelProperty, value);
    }
}

2 个答案:

答案 0 :(得分:1)

首先,我建议使用Catel.Fody,这会大大简化您的财产注册(是的,它还支持更改回调;-))。

为什么模型会从外部改变?当模型发生变化(它被注入你的ctor)时,它应该重新创建一个新的VM,因此你可以从一个新的平板开始。

回到这个问题:你测试过你的二传手是否真的被调用了吗?有可能Catel内部直接调用SetValue(等于依赖属性的行为),而不是调用vm中的包装器。 Catel以这种方式工作:

  1. 您更新模型
  2. 更改回调调用(因此您设置_canBeDirty =&gt; true)
  3. vm注意到模型已更改并更新公开/链接的属性。
  4. 我怀疑你基本上是在设置_canBeDirty =&gt;太早了。

答案 1 :(得分:0)

假设ViewModelBase遵守INotifyPropertyChanged订阅类&#39; INotifyPropertyChanged事件并在其中设置脏标志,而不是订阅单个更改事件。

根据定义,应该在设置任何值之后发生。

示例

public MyViewModel(MyModel myModel, IMyService myService)
 {
    ...
    this.PropertyChanged += (sender, args) => 
                            {
                                if (_canGetDirty)
                                    _myService?.AskForSaving();
                            };
 }

您可以使用args.PropertyName检查清除模式中的任何竞争条件逻辑。