Question

I'm trying the MVVM Light Toolkit. Though I still think having multiple ViewModels for such small apps is overkill, I like the concepts. What I still can't quite understand is how (or I should say "what is the recommended way") to navigate from one page to another when the selection changes in a ListBox.

The big problem with this toolkit is that it forces you to learn MVVM via other sources before using it, rather than show you what (its vision of) MVVM is from within the framework, accompanying samples and documentation. Are there samples out there showing the different concepts? And please, no videos.

Was it helpful?

Solution

Have you tried modifying your ListBox ItemTemplate to have each item be a HyperlinkButton and just setting the NavigateURI attribute to the Page you want to navigate to?

OTHER TIPS

I still have not figured out how to do this (navigate to a details page upon selection changed in a listbox) without any codebehind in the view. However, if you are OK with having just a little codebehind in the view here's what I recommend:

<ListBox x:Name="MainListBox" Margin="0,0,-12,0" ItemsSource="{Binding Items}"
    SelectionChanged="MainListBox_SelectionChanged" 
    SelectedItem="{Binding Path=SelectedListItem, Mode=TwoWay}">
    <ListBox.ItemTemplate>
         <DataTemplate>
              <StackPanel Margin="0,0,0,17" Width="432">
                  <TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                  <TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
              </StackPanel>
        </DataTemplate>
   </ListBox.ItemTemplate>
</ListBox>

First, per above bind to the SelectedItem property of the Listbox with a TwoWay binding to a property in your ViewModel (SelectedListItem in the above).

Then in your codebehind for this page implement the handler for MainListBox_SelectionChanged:

    // Handle selection changed on ListBox
    private void MainListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        // If selected index is -1 (no selection) do nothing
        if (MainListBox.SelectedIndex == -1)
            return;

        // Navigate to the new page
        NavigationService.Navigate(new Uri("/DetailsPage.xaml", UriKind.Relative));

    }

This is the only codebehind you need in your main view.

In your main ViewModel you need a SelectedListItem property:

    public const string SelectedListItemPropertyName = "SelectedListItem";
    private ItemViewModel _SelectedListItem;
    /// <summary>
    /// Sample ViewModel property; this property is used in the view to display its value using a Binding
    /// </summary>
    /// <returns></returns>
    public ItemViewModel SelectedListItem
    {
        get
        {
            return _SelectedListItem;
        }
        set
        {
            if (value != _SelectedListItem)
            {
                _SelectedListItem = value;
                RaisePropertyChanged(SelectedListItemPropertyName);
            }
        }
    }

Now, the trick to getting the context passed to your details page (the context being what list item was selected) you need to setup the DataContext in your Details view:

public DetailsPage()
{
    InitializeComponent();
    if (DataContext == null)
        DataContext = App.ViewModel.SelectedListItem;

}

Hope this helps.

eventually you'll want to do more than just navigate, potentially navigate after setting a custom object.

Here is a MVVM-light way of doing this.

You'll first want to bind your listbox selected item to a property in your viewmodel

<ListBox ItemsSource="{Binding Events}" Margin="0,0,-12,0" SelectedItem="{Binding SelectedEvent, Mode=TwoWay}">

Declare your SelectedEvent property

    public const string SelectedEventPropertyName = "SelectedEvent";

    private Event _selectedEvent;


    public Event SelectedEvent
    {
        get {return _selectedEvent;}

        set
        {
            if (_selectedEvent == value)
            {
                return;
            }

            var oldValue = _selectedEvent;
            _selectedEvent = value;

            // Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
            RaisePropertyChanged(SelectedEventPropertyName, oldValue, value, true);
        }
    }

You can then define an interaction trigger bound to the tap event

<i:Interaction.Triggers>
    <i:EventTrigger EventName="Tap">
        <cmd:EventToCommand Command="{Binding EventPageCommand, Mode=OneWay}"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

In your viewmodel, define your EventPageCommand as a RelayCommand:

public RelayCommand EventPageCommand { get; private set; }
public MainViewModel()
{
    EventPageCommand = new RelayCommand(GoToEventPage);
}

and finally declare your GoToEventPage method

private void GoToEventPage()
{
    _navigationService.NavigateTo(new Uri("/EventPage.xaml", UriKind.Relative));
}

note that you can do other actions before navigating to your new page, plus your selected item from your list box is currently set in the property you bound it too.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top