This is a specific question about the MVVM pattern best practice. I'm using MvvmLight Library.
It goes like this:
My model, say "Flight", implements some business logic that can start, pause and stop flights via methods. Each method does its logic to make the functionality happen whether it's playing stopping or pausing the flight. One important variable that changes is a status enum which indicates the flight status - playing, stopped, or paused. As said the status variable (and property) are defined in the Model.
On the other side the flight class is wrapped by a ViewModel class which contains a Status property that wraps the status variable in the flight model, and also RelayCommands that connect to the flight model play stop pause methods.
Here the problem begins:
When I execute one of the commands through the view, it executes the method in the model so that the status variable itself changes directly, but it only changes in the model.. The status property in the ViewModel doesn't know whether the wrapped variable have been changed, as it was changed directly... That means if some view element is binded to the status property, it won't change upon command execution..
I know several means to solve this but I'm asking for a fair solution that won't break the MVVM pattern (like using INotifyPropertyChanged in the flight class in the Model )
There is no magic bullet solution to this type of problem. Your ViewModel and Model need to be designed in a way that allows the information to propagate to the View; if this is not possible, then the design is flawed and needs to change.
Here's a couple of things you should look into:
If the Model's state-modifying methods are documented to execute synchronously, create methods on the ViewModel that forward the action to the Model and then immediately query its state. Use these methods for the implementation of the RelayCommands.
If the Model's methods are not synchronous then there should be some mechanism available to the Model's clients to notify them when the methods have completed. This can be done through continuation callbacks, events, or perhaps even with INotifyPropertyChanged.
As you mentioned above, your ViewModel should wrap Model at the following way:
class Model
{
public int State{get;private set;}
public void Fly()
{
State=1;
}
public void Stop()
{
State = 2;
}
}
class ViewModel : ViewModelBase
{
int State{ get{ Model.State;}}
...
OnFlyCommand()
{
Model.Fly();
NotifyPropertyChanged("State");
}
}
You could just call OnNotifyPropertyChanged just after the ViewModel executed the method on Model. That's not very elegant, but you just can't get any simpler without refactoring your Model class.
Do you know what properties have changed after the command is executed? I mean, can you explicitly raise change notification on specific set of properties or the set of modified properties is changing?
In the former case you invoke command and raise the event for those properties explicitly:
command.Execute();
NotifyPropertyChanged("PropA");
...
NotifyPropertyChanged("PropN");
In the second case you can either raise change notification event for every property of the Model class using reflection or you can use a smarter solution like PostSharp.Domain.Toolkit.
Best practice is to call viewmodel from command execution, than call model change from viewmodel, after which mark viewmodel state as changed
Related
I'm relatively new to WPF and MVVM and i am trying to understand how to use commands correctly when they have dependencies in more than 1 view model.
A couple of examples:
In my current application i have a RelayCommand which causes a save action to occur in a couple of different view models (they write a couple of different files). Currently i am handling this using a the mvvmlight messenger to send a message to those view models to get them to do the save which i think is the correct way to do it as it avoids having to provide some kind of delegate or event to/on those view models.
I have a RelayCommand in a view model that has a CanExecute method which relies on the state of 2 other view models. I've currently handled this via the mvvmlight messenger as well by having changes in the view models the CanExecute method depends on message that their state is now valid for the operation. This seems messy but the only alternative i could think of was to use a delegate or event effectively weaving the view models together which i believe i should be avoiding.
Is there some generally accepted way to deal with this which i am missing?
In general your view model layer should have a 1:1 relationship with your view, there should be no good reason for a "Save" function to exist in a view model which is then called by another view model.
What it sounds like you should be doing is putting that logic into a service i.e. something like this:
public interface ISerializationService
{
void Save(SomeData data);
}
Then you need an implementation for this service that does the actual work:
public class SerializationService : ISerializationService
{
void Save(SomeData data)
{
// actual save happens here
}
}
Your view models should then contain properties that point to instances of these services:
public class MyViewModel : ViewModelBase
{
[Inject]
public ISerializationService SerializationService { get; set; }
// called when the user clicks a button or something
private void ButtonClickCommand()
{
this.SerializationService.Save(this.SomeData);
}
}
The only question remaining is "What sets the value of SerializationService?", and for that you need a dependency injection framework. There are plenty out there, MVVMLight installs one itself, but Ninject is the de-facto standard. When implemented properly the injection framework will create all view models for you and then "inject" the dependencies, i.e. your SerializationService property, of type ISerializationService, will be initialized with an instance of your SerializationService class (which in a case like this will also be configured to be a singleton).
Dependency Injection takes a bit of work to get your head around but once you start using it you'll never look back. It facilitates complete separation-of-concerns whilst alleviating the need to pass pointers to everything all up and down your architectural hierarchy.
I am a newbie.
I am trying to build a WPF application using MVVM. So far I have bound my view model properties to my view. Pretty clean and nice. No code behind.
My business logic is to start one or several batch process based on user input. The background process will in turn update the status on the view’s processbar and/or textblock.
My question is
What is the most MVVM way to do this?
Shall I put the batch processing code directly in my viewmodel class? If yes my viewmodel class looks big (thousands of lines)
Or shall I make a separate class in BusinessLogic folder (layer) to house the batch logic? If so how can I reference the viewmodel (UI) properties for input/output in the business logic class? Just pass those properties into the business logic class/method as parameters? and if so it looks like I have to pass a lot of properties as parameters. Is this the common MVVM way?
Please guide me in the right direction.
Thanks,
The processing logic should not go in the view-model, but the view-model will "know" how to kick off the process, probably by instantiating some component and calling a method on it, passing any parameters that the user specified in the UI.
That component that does the processing can emit status events (messages, percent complete, or both). The view-model can subscribe to these events (and unsubscribe when processing is complete), and update its properties accordingly.
For example, you may have a view-model property like this:
public string StatusMessage
{
get { return _statusMessage; }
set
{
_statusMessage = value;
RaisePropertyChanged("StatusMessage"); // you need to implement INotifyPropertyChanged
}
}
Your component that does the processing may emit an event at 10% completion intervals and another event in the case of an error. You can subscribe to these events in the view-model and set the StatusMessage property to things like "Processing - 30% complete" or "Processing failed due to timeout."
I recently find out that wpf handles INotifyPropertyChanged in two different ways. I just wanna know what's the reason.
Let us take a normal twoway binding with validation true.
if you set a property from ui to viewmodel it goes like this.
setter call started
value set
INotifyPropertyChanged started
INotifyPropertyChanged done
setter done
getter called and done
IDataErrorInfo called and done
but if you set the property in your viewmodel it goes like this
setter call started
value set
INotifyPropertyChanged started
getter called and done
IDataErrorInfo called and done
INotifyPropertyChanged done
setter done
Changing property from UI to ViewModel may lead to deadlock kind of situation which might run into end less recursive calls in two way scenarios. In order to block this from happening, when WPF is making change to model, it will continue to track changes via INotifyPropertyChanged ,but this change will be queued in dispatcher queue, and it will be executed after its current update is finished.
Since the change in viewmodel is not initiated by WPF, WPF will not queue the operation, it will immediately execute the change.
My Model implements INotifyPropertyChanged, and I have a WPF window bound to it (two way bindings).
I need to know when the model is being changed through the bound UI, so I could call an Update method from another module (which then copies My model to it's internal structures).
Model can also be changed by another module.
How to tell (in my PropertyChanged event handler) if the change originated in my UI, and not in that other module?
I do not want to call Update method if it was the other module that triggered the PropertyChanged event.
I'm fairly new to WPF myself, but the only immediately obvious way I can think of to do this would be to add extra set methods to the model, that modify the backing store without directly changing the property and thus firing the PropertyChanged event. To remove duplication, the property setter should probably call those methods as well and there should be a boolean argument fireChangedEvent. Something like this:
public string SomeThing
{
get { return _someThing; }
set { SetSomeThing(value, true); }
}
public void SetSomeThing(string value, bool fireChangedEvent)
{
_someThing = value;
if(fireChangedEvent)
{
NotifyPropertyChanged("SomeThing");
}
}
Then, in the other module, it would be
public void DoStuff
{
// ...
model.SetSomeThing("foo",false);
// ...
}
It's not an elegant method I know, and I hope someone else can think of something smarter, but I can't think of a good way of finding out from inside a property setter what exactly is setting that property.
Hopefully this is at least a workaround suggestion.
There is another way: using Binding.SourceUpdated
Every binding on the window would have to be set NotifyOnSourceUpdated=true, and the common handler for SourceUpdated event would do the rest (raise the Window.ModelEdited event that would trigger Update on another module).
This question already has answers here:
How can I Have a WPF EventTrigger on a View trigger when the underlying Viewmodel dictates it should?
(4 answers)
Closed 8 years ago.
I have quite simple (I hope :)) problem:
In MVVM, View usually listens on changes of ViewModel's properties. However, I would sometimes like to listen on event, so that, for example, View could start animation, or close window, when VM signals.
Doing it via bool property with NotifyPropertyChanged (and starting animation only when it changes from false to true) is possible, but it feels like a hack, I'd much prefer to expose event, as it is semantically correct.
Also, I'd like to do it without code in codebehind, as doing viewModel.myEvent += handler there would mean that I'd have manually unregister the event in order to allow View to be GC'd - WPF Views are already able to listen on properties 'weakly', and I'd much prefer to program only declaratively in View.
The standard strong event subscription is also bad, because I need to switch multiple ViewModels for one View (because creating View every time takes too much CPU time).
Thank you for ideas (if there is a standard solution, a link to msdn will suffice)!
Some comments:
You can use the weak event pattern to ensure that the view can be GC'd even if it is still attached to the view model's event
If you're already switching multiple VMs in for the one view, wouldn't that be the ideal place to attach/detach the handler?
Depending on your exact scenario, you could just have the VM expose a state property which the view uses as a trigger for animations, transitions, and other visual changes. Visual state manager is great for this kind of thing.
This is something that I wrestled with as well...
Similar to what others are saying, but here is an example with some code snippets... This example shows how to use pub/sub to have a View subscribe to an event fired by the VM - in this case I do a GridView. Rebind to ensure the gv is in sync with the VM...
View (Sub):
using Microsoft.Practices.Composite.Events;
using Microsoft.Practices.Composite.Presentation.Events;
private SubscriptionToken getRequiresRebindToken = null;
private void SubscribeToRequiresRebindEvents()
{
this.getRequiresRebindToken =
EventBus.Current.GetEvent<RequiresRebindEvent>()
.Subscribe(this.OnRequiresRebindEventReceived,
ThreadOption.PublisherThread, false,
MemoryLeakHelper.DummyPredicate);
}
public void OnRequiresRebindEventReceived(RequiresRebindEventPayload payload)
{
if (payload != null)
{
if (payload.RequiresRebind)
{
using (this.gridView.DeferRefresh())
{
this.gridView.Rebind();
}
}
}
}
private void UnsubscribeFromRequiresRebindEvents()
{
if (this.getRequiresRebindToken != null)
{
EventBus.Current.GetEvent<RequiresRebindEvent>()
.Unsubscribe(this.getRequiresRebindToken);
this.getRequiresRebindToken = null;
}
}
Call unsub from the close method to prevent memory leaks.
ViewModel (Pub):
private void PublishRequiresRebindEvent()
{
var payload = new RequiresRebindEventPayload();
payload.SetRequiresRebind();
EventBus.Current.GetEvent<RequiresRebindEvent>().Publish(payload);
}
Payload class
using System;
using Microsoft.Practices.Composite.Presentation.Events;
public class RequiresRebindEvent
: CompositePresentationEvent<RequiresRebindEventPayload>
{
}
public class RequiresRebindEventPayload
{
public RequiresRebindEventPayload()
{
this.RequiresRebind = false;
}
public bool RequiresRebind { get; private set; }
public void SetRequiresRebind()
{
this.RequiresRebind = true;
}
}
Note that you can also set the constructor up to pass in a Guid, or some identified in, which can be set on Pub and checked on sub to be sure pub/sub is in sync.
imho yYand separated
state - to be able to move data back/forth between view <-> vm
actions - to be able to call onto view model functions/commands
notifications - to be able to signal to the view that something has happened and you want it to take a viewy action like make an element glow, switch styles, change layout, focus another element etc.
while is true that you can do this with a property binding, its more of a hack as tomas mentioned; always has felt like this to me.
my solution to be able to listen for 'events' from a view model aka notifications is to simple listen for data-context changes and when it does change i verify the type is the vm i'm looking for and connect the events. crude but simple.
what i would really like is a simple way to define some 'view model event' triggers and then provide some kind of handler for it that would react on the view side of things all in the xaml and only drop to code behind for stuff thats not do-able in xaml
Like adrianm said, when you trigger your animation off a bool property you are actually responding to an event. Specifically the event PropertyChanged which the WPF subsystem. Which is designed to attach/detach correctly to/from so that you don't leak memory (you may forget to do this when wiring an event yourself and cause a memory leak by having a reference active to an object which otherwise should be GCed).
This allows you to expose your ViewModel as the DataContext for the control and respond correctly to the changing of properties on the datacontext through databinding.
MVVM is a pattern that works particularly well with WPF because of all these things that WPF gives you, and triggering off a property change is actually an elegant way to use the entire WPF subsystem to accomplish your goals :)
A more general question to ask is: "Why am I trying to deal with this event in my ViewModel?"
If the answer has anything to do with view-only things like animations, I'd argue the ViewModel needs not know about it: code behind (when appropriate), Data/Event/PropertyTriggers, and the newer VisualStateManager constructs will serve you much better, and maintain the clean separation between View and ViewModel.
If something needs to "happen" as a result of the event, then what you really want to use is a Command pattern - either by using the CommandManger, handling the event in code behind and invoking the command on the view model, or by using attached behaviors in the System.Interactivity libs.
Either way, you want to keep your ViewModel as "pure" as you can - if you see anything View-specific in there, you're probably doing it wrong. :)