gcso
gcso

Reputation: 2345

MVVM alternate events pattern

I currently have a hierarchy that looks like this

MainWindowViewModel
    TabViewModel
        EditorViewModel
            ReviewingServices
                ConflictFinder

The issue I'm running into is that TabViewModel wants to be notified of conflicts (from ReviewingServices) as well as other things. I could create public getters for all my dependencies and subscribe to whatever I want with DependencyA.DependencyB.DependencyC += SomeHandler; but that's rather messy. I'm finding myself creating far too many events that I wish to count. Essentially, I've created a messy web of events. I love the separation of responsibilities that I've created for every class but when every class has 2-3 events each it's rather difficult to maintain. I'm having no issues creating and maintaining events if the subscriber is only 1 level above. The mess comes when say MainWindowViewModel wishes to be notified of new reviews (published from ReviewingServies.

Is there a better of doing these types of events where a subscriber could want to subscribe to events that are deeply nested in the application?

Upvotes: 0

Views: 219

Answers (3)

Ivan Zlatev
Ivan Zlatev

Reputation: 13196

Chaining DependencyA.DependencyB.DependencyC is generally considered breaking the Law of Demeter (you are effectively relying on a dependency of a dependency, etc).

I recently solved a similar design problem by using a Mediator defined by an interface such as IMyOperationNameContext which allowed me to share/inject the combined context of two ViewModels with/into a WinForms control which uses a third ViewModel and all of that without coupling the three models together directly.

Something like this (note how in the sample the IAlbumContext acts more as a proxy, but that's just because the sample is simplified):

interface IAlbumContext
{
    public AlbumInfo SelectedAlbum { get; set; }
}

class AlbumContext
{
    AlbumSelectionViewModel _model;

    public AlbumContext(AlbumSelectionViewModel model)
    {
        _model = model;
    }     

    public Album SelectedAlbum {
        get { return _model.Album; }
    }
}

class PhotoUploadDialog : Dialog
{
    public PhotoUploadDialog(IAlbumContext context, PhotoUploadViewModel viewModel)
    {
    }
}

While this solution worked for me and I like that it's with high cohesion and decoupled it's ultimately not massively scalable (e.g the number of such context interfaces can grow rapidly depending on the app). However with a more generic solution the trade-off is that the code gets harder to follow.

Upvotes: 1

Dean Chalk
Dean Chalk

Reputation: 20451

Try using Microsoft Prism and their Event Aggregator

Upvotes: 1

Felice Pollano
Felice Pollano

Reputation: 33252

I don't know if I really got your trouble, but I suggest to look at some kind of event aggregator. Try to check out the Caliburn one, but is not so different to implement one yourself. With this you name the event with a type and subscribe to it from everywhere.

Upvotes: 1

Related Questions