Different ViewModels, Same View

Aug 27, 2010 at 4:33 PM


I'm a recent convert from MVVMLight to nRoute and I must say that while I loved the simplicity of MVVMLight, your framework was the missing piece that was keeping my app from being incredible. I'm using the nNetflix app as the ideological starting place for porting my existing WPF application to your framework. I use 3 tiers of navigation, instead of just one. These tires are controlled by SiteMaps, but the nav containers are ListBoxes, and the items are filtered with nested CollectionViewSources.

In one section of the app, selecting the "Enums" 2nd tier nav loads up the 3rd tier nav with the available Enum Tables to edit (a list of which are defined in the SiteMap). Selecting the table loads up the DB values matching that criteria in the left column, but the right column view stays the same. This strategy is for editing database-bound enumerations, where the objects are structurally identical, but there is no common base type.

The other section of the app works in the opposite manner: selecting the 2nd tier determines the data type that will be edited in the left column, and selecting the 3rd tier changes which navigation property of the selection in the left column is going to be edited. So, for example, the 2nd level nav would select that you want to edit Schools. You select a school from the list, and then click the 3rd level nav to change the right column to edit all of the selected School's Teachers.

I really like what you did in that sample where you have a generic DataListingViewModelBase that can handle getting the data back for multiple types. Since my app has about 20 different areas that all generate the same List view, I've turned the left column "Listing" control into a generic control that can theoretically be used by multiple ViewModels to display lists of data. So, for the first scenario I mentioned, I'd have 6 different ViewModels that inherit from DataListingViewModelBase, like so:

[DefineNavigationContent("Views/Management/Enums/PackageTypes/", typeof(ListingView))]
public class PackageTypesListingViewModel
        : DataListingViewModelBase<PackageType, MyDataContext>

The problem is, when I try to load all of the navigation up, I get the following error: "Resource of type nRoute.ViewModels.IViewModelProvider with name 'MyAppName.Views.Management.Enums.ListingView' already exists." I'm assuming this is because the BridgeViewModelBehavior does a lookup for the View's type against the Services registered, so it can only be used once. However, I'd really like to *not* have to have a bunch of extra Views whose only XAML code is to load up my generic control. Something tells me I'm going to have to deal with it for the time being, tho.

In my mind, the fact that I was using SiteMaps, URLs, and NavigationContent attributes to annotate everything led me to believe that the lookups were URL based. When you add the DefineNavigationContent attribute, it should negate the need for the MapViewModel attribute, because you are saying already how the Model maps to the View given how you navigated there. Since it doesn't appear to do that, I'm not sure why you'd need to specify the View type in that attribute at all.

Because the DefineNavigationContent attribute actually gives you the ability to relate all three pieces of data, I think there is a solution to the problem, if you:

  1. Change the DefineNavigationContentAttribute to also do the work of the MapViewModel attribute, so you don't need both attributes on a ViewModel.
  2. When nRoute initializes, reflect through the assemblies and get all of the types that have the DefineNavigationContentAttribute and build an separate in-memory list of the ViewModel type, the View type, and the URL.
  3. Change the BridgeViewModelBehavior to first check to see if the View type is in the list described above.
    1. If it is, and the list also contains the just-executed URL, then use those two values to determine what ViewModel is used.
    2. If it isn't, use the current behavior.

Does that make sense? And by the way, thanks so much for your hard work with this.

Robert McLaws
Interscape Technologies, Inc.

Aug 27, 2010 at 4:53 PM

On Twitter, Rishi suggested that I just create a new class for the Views that inherits from the base view.

    public class SpecificTypeListingView : ListingView

While it's not *exactly* what I was looking for, it worked, and it doesn't clutter up my codebase with excess files. But I still think that the changes I suggested would be beneficial to nRoute, especially eliminating the redundant attributes.

Thanks Rishi for the quick response, and I hope this helps anyone else in the same position.

Robert McLaws
Interscape Technologies, Inc.