Unable to navigate to a view in Prism using ViewModel first approach

Topics: Prism v4 - WPF 4
May 26, 2012 at 5:31 PM
Edited May 26, 2012 at 5:34 PM

I am facing a problem switching to a view. Here is the code using composite Command :
Shell View Model :

private void Navigate(object navigatePath) // this method handls a composite command with a path set in XAML CommandParameter="{x:Type ViewModels:MainViewModel}"
    {
        if (navigatePath != null)
        {
           _regionManager.RequestNavigate(RegionNames.ContentRegion, navigatePath.ToString());
        }
    }

In the ModuleA Initialize method :
_container.RegisterType<IMainView,MainView>();
_container.RegisterTypeForNavigation<MainViewModel>();


RegisterTypeForNavigation is a Unity extension set like this :

 public static void RegisterTypeForNavigation<T>(this IUnityContainer container)
    {
        container.RegisterType(typeof(Object), typeof(T), typeof(T).FullName);
    }

When I click on the navigate button: I get only the full name of the view model Like : ModuleA.ViewModels.MainViewModel in the shell ! Am I doing anything wrong ?

Developer
May 28, 2012 at 7:13 PM

Hi,

As you are using view model first approach, when you navigate to an specific view model, that view model will be injected in the Region, not its corresponding view. And as the view model does not have a visual representation on its own, it's rendered as its string representation.

Based on my understanding, if you wish to use navigation and view model first approach you will need to use DataTemplates in the corresponding regions as mentioned by Guido Maliandi in this thread.

For example, if you have a region named "MainRegion" and you will navigate on that region using view model first, you could define a DataTemplate for each view model you have, so that it creates the associated view when a view model of the corresponding type is injected in the region:

<ItemsControl Name="MainRegion" cal:RegionManager.RegionName="MainRegion" >
    <ItemsControl.ItemTemplate>
        <DataTemplate DataType="viewModels:MainViewModel">
            <views:MainView/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

The view model you injected into the region will be automatically set as the DataContext of the view.

However, I believe a better approach could be to have each view model to hold a reference to its corresponding view and show that view through data binding. For example, if all of your view models implement an interface named IViewModel which defines a View property, which will be used by the view models to expose their views, you can simply define a generic DataTemplate that should work for all of your view models in a more decoupled fashion:

<ItemsControl Name="MainRegion" cal:RegionManager.RegionName="MainRegion" >
    <ItemsControl.ItemTemplate>
        <DataTemplate DataType="infra:IViewModel">
            <ContentControl Content="{Binding View}"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Also, I believe you could find the following thread interesting were a similar topic was discussed:

I hope you find this useful,

Damian Cherubini
http://blogs.southworks.net/dcherubini

May 29, 2012 at 8:06 PM

Hi DCherubini,

I would like to thank you about your intresting reply.

Fortunately I knew my mistake.

Mr.Brian Lagunas has recommended me using View first approach. so I've changed all my project implementing it. and everything is working well up to now.

Thnaks