0

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?

Kit
  • 20,354
  • 4
  • 60
  • 103
  • you can implement [ISupportInitialize](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.isupportinitialize) and ignore changes between `BeginInit/EndInit`. Alternatively expose method `MarkAsUnmodified()` and reset tracking when needed. – Liero Nov 16 '22 at 12:44

2 Answers2

0

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.

sotonika
  • 161
  • 1
  • 5
0

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.

Pavel Gatilov
  • 7,579
  • 1
  • 27
  • 42
  • I agree with you about the coupling issue. The need to do something outside both view and view-model leads me to think MVPVM: http://msdn.microsoft.com/en-us/magazine/hh580734.aspx. – Kit Dec 12 '11 at 18:09
  • @Kit I haven't heard of the MVPVM earlier, but at a glance it seems to be a synonym to the MVCVM (C is for Controller). It's a discussion question, but I just don't like the idea that extracting coupling into a separate component removes coupling. For me, I just get 3 coupled classes instead of 2. I usually try to write some adapters to wrap a bad control into a binding-friendly interface. But perhaps I'm an MVVM extremist. – Pavel Gatilov Dec 12 '11 at 18:28
  • It seems like a partial attempt to go back to SRP (http://stackoverflow.com/questions/7164412/are-current-mvvm-view-model-practices-a-violation-of-the-single-responsibility-p) but just pushes it into super-coupled presenter/controller. – Kit Dec 12 '11 at 20:01
  • @Kit Kind of. As far as I understand it, R is the main letter in the SRP. For me, the responsibility of view models is getting rid of all presentation-related stuff and expressing the UX logic in POCO classes. And views are a separate layer that manages itself and lives on top of the VM layer. Even windows are opened by other views. The only place where VM an V meet in code is the application startup. Does this violate the SRP? I don't think so because of the way the R is defined. And it seems to be consistent with [Martin Fowler](http://martinfowler.com/eaaDev/PresentationModel.html) – Pavel Gatilov Dec 13 '11 at 02:14