سؤال

I have need of a view model that tracks changes so the user can see things visually change in response to edits and rollback portions. Right now, I "turn on" change tracking as the last step in the constructor for the view model (necessary, because sometimes the view models are constructed from templates or have defaulting logic that triggers PropertyChanged before construction is complete, erroneously leading one to think it's changed even before the user has done anything).

This has worked for the most part,

  • but with more complicated controls, bindings, and lack of controlling the order for various events in third-party products
  • and, a need to turn on change tracking after view model is built from a DTO returned from a service call (i.e. the model-model),

is there a better place to turn-on change tracking?

هل كانت مفيدة؟

المحلول

In an ideal MVVM implementation there's neither better nor alternative place, because you aren't likely to know when or how a view communicates with a view model. In fact, a view model shouldn't know anything about a view. A view might be a Silverlight UI or a console app, or a test mock-up, or whatever else. According to general thoughts then, constructor seems to be the only place where 'change tracking' should be disabled.

If you try following the MVVM strictly, you should accept your view models as main objects and views as secondary ones. I mean a view shouldn't introduce any logic that doesn't relate to the specific view implementation. It only displays the current view model state and communicates a user's actions to the view model. If it's true, then you won't need to turn change tracking off wherever except the constructor.

Of course, in the real world this might get rather difficult to follow. If you can't find another solution, you could introduce additional properties to the view model, e.g. IsViewInitialized, which would turn on 'change tracking', and make the view set the property as required.

But you'd better avoid this as long as possible. Such an approach increases coupling between Views and ViewModels which is against one of the main ideas of the MVVM pattern.

If you'd ask me in personal, my view models quite rarely have an alternative logic for the initialization steps and if they do, it's only in the constructors. And I usually don't 'turn off change tracking' but rather set some fields directly to get around the regular change tracking code that for most cases resides in property setters. But sometimes it's more convinient to trigger that logic for some properties even in a constructor.

نصائح أخرى

Generally, there is no "right" or "wrong" place to handle change tracking.

But if you prefer to do it inside VM, your RaisePropertyChanged() method can accumulate list of changed properties (changesList). You should implement public (possibly virtual) method ApplyChanges(), that clears this list and saves data (if you post changes through network, add more checks so you don't send the same data over and over). Also, have public property bool IsChanged { get; }, that returns changesList.Any() -- you can use this property to bind your "Apply" buttons to.

For your case: in complex constructors, invoke ApplyChanges() to reset IsChanged state, and after complex controls are bound to your VM, also invoke ApplyChanges() - even if you know user didnt do anything yet.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top