2

Switching for the first time ever from WPF to UWP I found out that there are great controls like SplitView and NavgiationView do exist in the world of UWP.

For renewing my current home-project I have choosen the NavigationView control as my main UI control for offering the various pieces of information. Using the code-behind the page navigation (as shown here) is very easy, but for my use-case I want to work with MVVM (as a learning procedure without using FWs like MVVMLIght or similar).

Currently, my NavigationView looks like this; but I have not a proper idea how to change within the frame through pages (from my understanding I have to use the NavigationService but haven't found a easy to understand example of this):

<NavigationView x:Name="nvTopLevelNav" Grid.Column="0" Grid.Row="1" Grid.RowSpan="3" IsPaneOpen="False"  IsPaneToggleButtonVisible="False" CompactModeThresholdWidth="0" IsBackButtonVisible="Collapsed" Background="Black" Foreground="Black"
        Loaded="nvTopLevelNav_Loaded"
        Margin="0,12,0,0"
        SelectionChanged="nvTopLevelNav_SelectionChanged"
        ItemInvoked="nvTopLevelNav_ItemInvoked"
        IsTabStop="False"
                IsSettingsVisible="False"
                AlwaysShowHeader="False"
        Header="asdasdaasdasdasd">
    <NavigationView.MenuItems>
        <NavigationViewItem Icon="Home" Content="Home" Tag="Home_Page" />
        <NavigationViewItem Icon="Globe" Content="Weather" Tag="Weather_Page" />
        <NavigationViewItem Content="My Agenda" Tag="Agenda_Page">
    <!-- some custom PathIcon -->
        </NavigationViewItem>
        <NavigationViewItem Icon="Contact" Content="My News" Tag="News_Page" />
    </NavigationView.MenuItems>
    <Frame x:Name="contentFrame"></Frame>
</NavigationView>
mbed_dev
  • 1,450
  • 16
  • 33

2 Answers2

1

UWP NavigationView switch to another page via MVVM

For your requirement, you could use Windows Template Studio to create UWP project that contain MVVM pattern and NavigationService.

private void OnItemInvoked(NavigationViewItemInvokedEventArgs args)
{
    if (args.IsSettingsInvoked)
    {
        NavigationService.Navigate(typeof(SettingsViewModel).FullName);
        return;
    }

    var item = _navigationView.MenuItems
                    .OfType<NavigationViewItem>()
                    .First(menuItem => (string)menuItem.Content == (string)args.InvokedItem);
    var pageKey = item.GetValue(NavHelper.NavigateToProperty) as string;
    NavigationService.Navigate(pageKey);
}

enter image description here

Nico Zhu
  • 32,367
  • 2
  • 15
  • 36
  • 1
    I have to admit this is the solution, but the code is not really self-explanatory. It uses "ActionServices", which agian are completely new for me. But thank you anyways – mbed_dev Oct 21 '18 at 13:50
0

Have a read of my blog about solution i came up with without any 3rd party api, there is also github repot with the solution.

https://kwodarczyk.github.io/UwpWinUI3PageMVVMNavigation/

All you need it attached property that allows to pass view model type to your datatempalte

public class ViewModelContext : DependencyObject
{
    public static readonly DependencyProperty TypeProperty =
    DependencyProperty.RegisterAttached(
      "ViewModelContext",
      typeof(Type),
      typeof(ViewModelContext),
      new PropertyMetadata(null)
    );
    public static void SetType(DependencyObject element, Type value)
    {
        element.SetValue(TypeProperty, value);
    }
    public static Type GetType(DependencyObject element)
    {
        return (Type)element.GetValue(TypeProperty);
    }
}

example datatempalte:

<DataTemplate x:Key="PageOne" viewModels:ViewModelContext.Type="viewModels:PageOneViewModel">
   <views:PageOne/>
</DataTemplate>

and custom template selector where you can match the template agatis the view model

public class CustomTemplateSelector : DataTemplateSelector
{
    protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
    {
        if (item != null)
        {
            var viewModeltype = item.GetType();

            foreach (var rd in Application.Current.Resources.MergedDictionaries)
            {
                foreach (var value in rd.Values)
                {
                    if (value is DataTemplate dataTempate)
                    {
                        Type contexType = dataTempate.GetValue(ViewModelContext.TypeProperty) as Type;

                        if (contexType != null && contexType == viewModeltype)
                        {
                            return dataTempate;
                        }
                    }
                }
            }
        }
        return null;
    }
}
IronHide
  • 327
  • 1
  • 3
  • 17