1

I know there are a lot of questions about WPF navigation, for application developed with MVVM pattern, and I have read tens and tens of answers but I'm missing probably something. I started building an application following Rachel's article here. All works just fine, there's an ApplicationView Window with this XAML:

<Window x:Class="CashFlow.ApplicationView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="clr-namespace:CashFlow.ViewModels"
    xmlns:v="clr-namespace:CashFlow.Views"
    Title="ApplicationView" Height="350" Width="600" WindowStartupLocation="CenterScreen">


<Window.Resources>
    <!--Here the associations between ViewModels and Views-->
    <DataTemplate DataType="{x:Type vm:HomeViewModel}">
        <v:HomeView />
    </DataTemplate>
</Window.Resources>

<!--Define here the application UI structure-->
<DockPanel>
    <Border DockPanel.Dock="Left" BorderBrush="Black" BorderThickness="0,0,1,0">
        <ItemsControl ItemsSource="{Binding PageViewModels}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button Content="{Binding Name}"
                            Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
                            CommandParameter="{Binding}"
                            Margin="2,5" />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>            
    </Border>

    <ContentControl Content="{Binding CurrentPageViewModel}" />

</DockPanel>

The ApplicationViewModel, that is set as DataContext for this window when the application starts, maintains an ObservableCollection of my ViewModels. Thanks to data templates, it's possible to associate every view with its viewmodel, using a ContentControl to render the views. Navigation in this case is accomplished with a "side bar" of buttons, binded to ApplicationViewModel commands that perform the changes of CurrentPageViewModel object. I'm wondering how I can perform navigation without the presence of that sidebar of Buttons. Having only the Content control, I should be able to change the CurrentPageViewModel from the others viewmodel? Probably the answer will be very trivial, but I can't see that right now.

Dan
  • 163
  • 1
  • 8
  • "I should be able to change the CurrentPageViewModel from the others viewmodel": what do you mean by this? Are you saying you want to change the viewmodel of a page dynamically? If so, based on what condition(s)? – Peter Ritchie Sep 18 '14 at 16:28
  • Hi Peter, I mean that in the example above, if I remove the buttons binded to ApplicationViewModel commands, how can the Views interact with the ApplicationViewModel? Should I bind views' controls to ApplicationViewModel's commands or bind them to properly commands defined in viewmodels that then perform in some way the changing of the current viewmodel? – Dan Sep 18 '14 at 16:42

2 Answers2

1

Your top level homeviewmodel can orchestrate navigation via an eventbus pattern. To use eventbus, you would inject an object that tracks objects that want to be notified of events. Then when a view model raises an event, the homeviewmodel receives it and performs the currentpageviewmodel assignment that will navigate you to the next viewmodel.

Ex:

Messenger defines two methods - RegisterForEvent<IEvent>(ViewModel aViewModel), and RaiseEvent(IEvent event).

So you would define a function to subscribe to the events -

HomeViewModel.cs

...
void SubscribeForEvents() {
    Messenger.RegisterForEvent<NavigationEvent>(this);
}

Then you inject the Messenger into your other view models, and from those view models, raise the event:

Messenger.RaiseEvent(new NavigationEvent { TargetViewModel = new TargetViewModel() });

Where the event is something like

public class NavigationEvent : IEvent {
    ViewModel TargetViewModel { get;set;}
}
C Bauer
  • 5,003
  • 4
  • 33
  • 62
0

C Bauer is right with what you are missing. I found in order to switch the data context, you'll need a messenger service to flag your "applicationviewmodel" to switch its data context. A good discussion with the steps you need are spelled out in a discussion here.

Register the message to be received in your applicationviewmodel, then handle the data context switch in your receive message function.

Also, this might be true or not, but I had to use 1 window, with multiple user controls as opposed to multiple windows if I wanted to have 1 window showing at all times. Lastly, I followed Sheridan's example and defined my data templates in my app.xaml as opposed to the window itself.

Community
  • 1
  • 1
Stunna
  • 413
  • 6
  • 16