Does the 'PropertyChanged' event keep Views alive for the life of models that use it? - wpf

Does the 'PropertyChanged' event keep Views alive for the life of models that use it?
For instance, does this code not keep the view alive for the life of the view model?
public MyView(MyViewModel a_viewModel)
{
Loaded += (s, e) =>
{
DataContext = a_viewModel;
};
}
OK, bad example. Here is the code I'm actually worried about in my ViewModelBase class:
protected void RelayPropertyChanges(INotifyPropertyChanged a_source, String a_strSourceProperty, String a_strTargetProperty)
{
ValidatePropertyExists(a_strTargetProperty);
if (a_source is ViewModelBase)
(a_source as ViewModelBase).ValidatePropertyExists(a_strSourceProperty);
a_source.PropertyChanged += (s, e) => OnPropertyChanged(a_strTargetProperty);
}
And, I just realized that this won't work right. I'll get back to you guys on this; any ideas on ways to make this work?

The "PropertyChanged" event is no different than any other event, so let's discuss events in general.
When an instance of your view (we'll call it V) subscribes to an event on the model (M), it hands a reference of itself to the model in the delegate. So M now holds a reference to V. If you continue to use M in other code, yes - that reference will keep the instance of V from being garbage collected.
You can remove this concern by "unsubscribing" to the event in the View, or making sure your model doesn't outlive it by too long (in which case it's probably just not a problem). There are other approaches where people use "weak events" - but this requires some modification to your design and is not "built-in" to the framework or language (see articles like http://kutruff.wordpress.com/2009/03/06/high-performance-property-changed-weak-event-notifications-for-c/)
Since you ask about "PropertyChanged" specifically, you are probably worried about databinding (and you've tagged with WPF). In this case the answer is "probably not". The data binding manager is "smart" enough to weakly reference the view if you inherit from INotifyPropertyChanged or use Dependency Properties. If not, and you are not using OneTime binding, then the view will not be collected when you think it should (see this KB for more info http://support.microsoft.com/kb/938416 )

Related

Correct way to handle commands that rely on multiple view models

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.

MVVM design choice regarding responsibility of ViewModel for simple states

I've recently started to delve into MVVM architectural pattern. I've understood large parts of it but still few doubts remain regarding how much responsibility ViewModel should take on behalf of View.
In other words, how dumb should View be?
For example, for simple state coordination like clearing TextView after user presses SubmitButton. This kind of state coordination requires no more than one-liner to implement using some of the popular data-binding frameworks.
For example in pseudo-ReactiveCocoa:
textView.text <~ submitButton.pressed.map { _ in "" }
However, Martin Fowler wrote in his Presentation Model,
The Presentation Model contains the logic that says that the composer field is only enabled if the check box is checked, so the when the view updates itself from the Presentation Model, the composer field control changes its enablement state
which suggests that even the simple logic like clearing out TextView after pressing Button should be encapsulated inside ViewModel.
Such design choice leads to something like this (again, in pseudo-ReactiveCocoa):
// In View
viewModel.submitButtonPressed <~ submitButton.pressed
textView.text <~ viewModel.textViewText
// In ViewModel
textViewText <~ viewModel.submitButtonPressed.map { _ in "" }
Although it leads to better encapsulation of logics while assuming view with the job of binding only (making it dumb), it does make code a lot more verbose and lead to tighter coupling between View and ViewModel (by requiring ViewModel to be aware of SubmitButton).
I'm still new to MVVM pattern in general and learning stuff every day.
How much responsibility should ViewModel take?
In other words, must View be completely dumb and only handle simple binding (connect its UI elements to bindable property provided by ViewModel) or is it okay for View to handle fairly simple logic like the above?
On a side note, is tight coupling between View and ViewModel okay in MVVM?
In general, the ViewModel takes all responsibility. More specifically, in your scenario, the ViewModel wouldn't know about the submitButton, but rather the View would know that the ViewModel exposes a command (an ICommand) called SubmitCommand, and have the submitButton bind to that command.
Sometimes it can get a bit more involved to completely separate the actions and corresponding logic, for instance when there's no binding available for a command for a specific event. But in those cases a fairly simple attached behavior (i.e. InvokeCommandAction and friends, see the documentation) can bridge that gap to coax flow so the logic can go in to the ViewModel.
Very rarely, there are scenarios (of which none come to mind currently) where it gets so involved that I just skip the whole idea, and separate as much as possible, rather than to have to work out three months later exactly what the hell is going on. But those cases are rare indeed.
In other words, must View be completely dumb and only handle simple binding
It's quite good, when view contains data bindings only, but IRL complex views can contain some view-specific logic. E.g., since single view model could be connected to a several views, focus management is a view's prerogative. Another sample is a logic like "hide element A if element B is disabled", or "change color from A to B if button is checked", etc.
XAML frameworks provide several techniques to make view logic more well-composed: commands, triggers, attached behaviors, value converters. But sometimes you actually need code-behind.
For example, for simple state coordination like clearing TextView
after user presses SubmitButton
To be more clear. This is not a view logic, and must be placed in view model:
public class ViewModel
{
private string someText;
public string SomeText
{
get { return someText; }
set
{
if (someText != value)
{
someText = value;
OnPropertyChanged();
}
}
}
private ICommand submitCommand;
public ICommand SumbitCommand
{
if (submitCommand == null)
{
submitCommand = new RelayCommand(() =>
{
// do submit
// clear text
SomeProperty = null;
});
}
return submitCommand;
}
}
XAML:
<TextBox x:Name="SomeTextBox" Text="{Binding SomeText}"/>
<Button Content="Submit" Command="{Binding SubmitCommand}">
But this is a view logic:
public MyWindow()
{
InitializeComponent();
// SomeTextBox should have initial focus
Loaded += (sender, args) => SomeTextBox.Focus();
}
is tight coupling between View and ViewModel okay in MVVM?
Ideally all components should be loosely coupled, but view must know about view model properties to perform data binding.

In a constructor for a WPF Window, what should go before InitializeComponent() and what after?

In general, I've been initializing the properties of the Window itself before InitializeComponent() and setting up controls contained within afterwards. However, I haven't been all that consistent, and I haven't really noticed a problem with the ordering. So:
Am I (potentially) doing something horrible? In particular, are there any issues with setting properties of child controls before InitializeComponent()?
What is good style in this regard?
Edit: Since the first two answers I got were a little bit contradictory, let me be more specific:
public Foo Foo {get; protected set}
public FooWindow (Foo foo)
{
Foo = foo;
this.Closing += FooWindow_Closing;
Foo.Frobbed += Foo_Frobbed;
InitializeComponent();
this.DataContext = this;
this.Title = Foo.Name() + " Window";
FooListView.ItemSource = Foo.CalculateList();
FocusManager.SetFocusedElement(this, FooListView);
}
Is this about right? Should I just be doing MVVM and not have anything in my Window constructor?
By calling InitializeComponents after some other code you run the risk of accidentally overwriting properties with things that were set in the XAML or of using an uninitialized object. Usually the code-behind is a higher priority than the XAML so I would leave InitializeComponents (aka, parse and load the XAML) at the top.
In answer to your specific questions:
Am I (potentially) doing something horrible? In particular, are there any issues with setting properties of child controls before InitializeComponent()?
Chances are that your child controls aren't available to you in code yet until you've called InitializeComponents. It would generally be bad form to do this.
What is good style in this regard?
This is going to be a matter of taste, but generally I would recommend that if you're going to take advantage of the separation that XAML affords you then I would take it as far as you can. If you're doing things that are logically about the UI try to do it in XAML. This isn't so much an MVVM thing as it is a separation of presentation from logic. Most of what you have in your sample code can be done declaratively, even if just through ValueConverters.
E.g if Foo was a DependencyProperty then you could also attach it in XAML and add the callbacks as part of the ValueChanged callback. Again, this isn't MVVM, but it is pretty fundamental to WPF.
For most other things, you actually probably want to wait until OnLoaded is called, rather than doing the work in the constructor.
Hope that helps,
I usually call anything that does not require the Visual Tree before I call InitializeComponent().
All of my implementations use the MVVM pattern, so I prefer to have my ViewModel instantiated and populated before the UI is loaded to the client.
If you always load InitializeComponent() first, you run the risk of creating a bad user experience by showing an unpopulated view that suddenly updates versus one that is populated when it comes into view.

MVVM and multi threading

Right, sticking with the MVVM focus for the minute, there are a small number of scenarios where threading may occur:
As usual, for simplicity we have a Model class, ViewModel class and View class.
The Model has a Collection and a string property.
1) User triggers long running background task. View triggers ViewModel. Can easily be managed by ViewModel using, for example, BackgroundWorker
2) Thread updates Model, ViewModel notified by Model of changes.
Previously we've discussed using INotifyChanged to notify changes from Model to ViewModel. The DependencyProperty system appears to marshal these to the correct thread for you.
For ObservableCollections this does not work. Therefore should my model's public face be single threaded (Don't like, why should the Model know about threads) or would I replicate some parts of the Model (For example the Collection above) in the ViewModel to ensure that amendments are made on the correct thread?
I think I've sort of answered my own question. Perhaps not. My Model does know about threads, so perhaps it's only polite to markshal them back using the IMarshalInvoker idea mooted earlier by Colin?
Some of my problem here is that I consider MVVM to be yet another MVC variant, and historically I've been happy to use terms like MVP, MP, MVC pretty much interchangeably because I knew what worked with the GUI technology (usually winforms) on the V end. When I say MVVM I'm specifically looking for practical advice on what works for WPF and WPF specific foibles. I hope that explains the nature of my questions and why I'm asking them.
I don't think it's a very good idea to go all-out and implement collections in your Model as ObservableCollection, as this is "polluting" your Model in a way that's only useful to WPF.
INotifyPropertyChanged is OK because:
There are many scenarios where having the ability to "listen in" is useful.
It can be utilized from pretty much any .NET code, not just WPF.
It doesn't give you any trouble if you want to serialize your Model.
So, I suggest to not have your model know about threads. Make your ViewModel know about threads, like this:
class Model {
List<Widget> Widgets { get; private set; }
}
class ModelViewModel {
ObservableCollection<Widget> Widgets { get; private set; }
ModelViewModel(Model model) {
this.Widgets = new ObservableCollection<Widget>(model.Widgets);
}
}
If Widget is a reference type and implements INotifyPropertyChanged (which would be about 100% of the time), this gets you most of the way:
Changes to any widget will be made to model itself and will reflect upon bindings immediately
Updates to the collection will reflect upon bindings immediately
There's still the problem that updates to the collection (adding and removing items) will not be made to model directly. But that can be arranged:
ModelViewModel(Model model) {
this.Widgets = new ObservableCollection<Widget>(model.Widgets);
this.Widgets.CollectionChanged += this.PropagateChangesToModel;
}
void PropagateChangesToModel(object sender, NotifyCollectionChangedEventArgs e) {
// do what the name says :)
}
Finally, you need to make ObservableCollection play well with being updated from a worker thread. This is a really common issue with WPF, and I refer you to the answer to this question for a solution: ObservableCollection and threading.

WPF: how to signal an event from ViewModel to View without code in codebehind? [duplicate]

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. :)

Resources