ViewModel Event Registration and ViewModel Lifetim

2019-07-26 21:21发布

I have an architectural problem, and a possible solution for which I would like an opinion.

I'm used to MVVM architecture for WP7 (whenever possible but unfortunately sometimes the sdk seems to go on the opposite direction).

WP7 force an ViewFirst approach and I feel confortable with this (except for the part that we can't override the View creation, as in Silverlight, to made constructor injection possible). I found myself confident by having most of the viewmodel follow the lyfetime of its view. So the viewmodel is created when the view is created (by accessing a ViewModelLocator), the ViewModel is (or should) be referenced only by its view, when the view is destroyed also its ViewModel should be destroyed (its not mandatory but its the way i go except in very rare case for which i create a singleton viewmodel).

My viewmodel could need to register to some singleton service events (phoneservice or singleton class i created). I mean, it could need to register to an event of a class which lifetime is not decided by the viewmodel itself. These events keep an hardreferences to my viewmodel and keep my viewmodel alive even when the view is destoryed, not only, my viewmodel will continue to receive and process the events. The WeakEvent pattern could be a possible solution but it's unpractible to create an eventmanager for every event. The best solution, in my opinion, does not exist and should be a keyword for a weak registration to events.

A solution I found is to have my viewmodel aware of NavigateTo and NavigateFrom so i can register and unregister events from there. I can also add some logic (for example i could unregister only in case of back) putting attention to have specular logic in NavigateTo and NavigateFrom.

Another possible way (I have not tested) could be to make my viewmodel aware of View finalization and perform some cleanup when the view is finalized but I always had the feeling the this approach is not reccomended beacuse of the use of the finalization. Also it's not clear to me how much the performance will be affected.

What do you think about having the viewmodel lifetime be the same as its view (it always simplified my app until now) ? What do you think about the NavigateTo-NavigateFrom ViewModel aware solution ? What do you think about the View-Finalization ViewModel aware solution ? Have you experienced any of these or maybe another type of solution ?

Regards SkyG

UPDATE

I found that the finalization solution will not do the work beacuse it can happen in late future (or maybe never). For now it seems to me that the best solution is a pair of virtual method in the viewmodelbase Initialize and Cleanup for event registration deregistration which the view should call. A Possible moment to call them could be during loaded and unloaded event (when I don't need my viewmodel process the event if I'm in a subsequent view, in this this case the first view/viewmodel are still alive in the backstack but loaded/unloaded are fired if they view is attached/detached to the visual tree).

Any other opinion (even confermative) will be appreciated.

Thank You

2条回答
爷、活的狠高调
2楼-- · 2019-07-26 21:45

What do you think about having the viewmodel lifetime be the same as its view (it always simplified my app until now) ?

This sounds reasonable to me, as it's directly related to the DataContext of the view.

What do you think about the NavigateTo-NavigateFrom ViewModel aware solution ?

I don't think it's a good idea. In the MVVM pattern, ViewModels are supposed to know nothing about the view. Navigation is typically related to views, so I don't think it's the best idea.

What do you think about the View-Finalization ViewModel aware solution ?

Without specifically talking about finalization, a clean-up method for view models is IMO the way to go. In the base class for all your ViewModels (I hope you have one), you could put the following method:

public abstract class ViewModelBase
{
    ....
    public virtual void Cleanup();
}

Then, simply call myViewModel.CleanUp(); when your view is closed. Unregister your events in the concrete implementation of CleanUp:

public override void CleanUp()
{
    ....Event -= this....EventHandler;
}
查看更多
Luminary・发光体
3楼-- · 2019-07-26 22:02

I agree that the weak event idea is nice but it would be too cumbersome to implement. It also creates issues of its own - it can make the viewmodel entirely weak-referenced, making it a candidate for garbage collection way before it actually "should" (developer opinion vs garbage collector opinion). I've been bitten by this before as has Ward Bell in this blog post of his.

Based on your requirements and desire to follow a "pure" approach to MVVM (viewmodel doesn't know about the view), it seems like you are struggling with the balance between the "view" and the "model" of the viewmodel. In this case, I'd actually suggest another design pattern: MVPVM (model / view / presenter / viewmodel). Here's an MSDN article on it.

In your case, the presenter would hold on to those singleton events. It would be okay for the presenter to know about the view because the presenter isn't meant to be reused across views. Your viewmodel would then just become a "model of the view", allowing for reuse and eliminating most vm lifetime issues.

I like the MVPVM approach because it always concerned me in MVVM when my viewmodels started to take on too much responsibility (talking to the data access layer, listening to application-wide events as well as handling commands from the view, maintaining its properties for the view, etc). I know this isn't necessarily an answer to your question but it's too long for a comment.

查看更多
登录 后发表回答