Help with frame navigation mvvm
I have been trying to navigate with a frame and NavigationView, without success
I Install Microsoft mvvm toolkit and behaviors (to be able to respond from a view Model).
I thought it was going to be easy, just create a property to catch the selected item and a command, to navigate and pass the frame to the method
Selected Item is null (when I change)
<NavigationView
Background="{ThemeResource AcrylicBackgroundFillColorBaseBrush}"
IsBackButtonVisible="Collapsed"
IsSettingsVisible="False"
PaneDisplayMode="LeftCompact"
SelectedItem="{x:Bind ViewModel.SelectedItem}">
I found this, so apparently is bug (because I did this exact same thing in wpf and it work in the first attempt), I wanted to use WinUI 3, because is the evolution of wpf, and I think is mature enough
https://github.com/microsoft/microsoft-ui-xaml/issues/2691
So, I thought "If I want to use MVVM, and passing a frame to a command is not very good practice, why I don't send a message to the view when I change, and tell the view to navigate", that way the viemodel doesn't know anything about the view
So, I changed my VM a little
[ObservableObject]
public partial class NavWindowViewModel {
private NavigationViewItem _selectedItem;
[RelayCommand]
private void NavigateToPage(object obj) {
var args = obj as NavigationViewSelectionChangedEventArgs;
_selectedItem = args.SelectedItem as NavigationViewItem;
if (_selectedItem != null) {
// Send the selected item as a message
WeakReferenceMessenger.Default.Send(_selectedItem);
}
}
}
}
and my code behind
public sealed partial class NavWindow : Window {
public NavWindowViewModel ViewModel { get; set; }
public NavWindow(NavWindowViewModel viewModel) {
InitializeComponent();
ViewModel = viewModel;
// Subscribe to the message
WeakReferenceMessenger.Default.Register<NavigationViewItem>(this, HandleSelectedItemMessage);
}
private void HandleSelectedItemMessage(object recipient, NavigationViewItem message) {
if (message != null && NavFrame != null) {
NavFrame.Navigate(message.GetType());
}
}
as you can see neither the Frame nor the message are null
this is my view, just in case
<NavigationView
Background="{ThemeResource AcrylicBackgroundFillColorBaseBrush}"
IsBackButtonVisible="Collapsed"
IsSettingsVisible="False"
PaneDisplayMode="LeftCompact">
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="SelectionChanged">
<Core:EventTriggerBehavior.Actions>
<Core:InvokeCommandAction Command="{x:Bind ViewModel.NavigateToPageCommand}" />
</Core:EventTriggerBehavior.Actions>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
<NavigationView.MenuItems>
<NavigationViewItem
Content="Manage class"
Tag="ManageClassPage">
<NavigationViewItem.Icon>
<BitmapIcon UriSource="ms-appx:///Icons/classroom.png" />
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem
Content="Create meeting"
Tag="CreateMeeting">
<NavigationViewItem.Icon>
<BitmapIcon UriSource="ms-appx:///Icons/meeting.png" />
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem
Content="Join meeting"
Tag="CreateMeeting">
<NavigationViewItem.Icon>
<BitmapIcon UriSource="ms-appx:///Icons/join.png" />
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem
Content="Report card"
Tag="ManageClassPage">
<NavigationViewItem.Icon>
<BitmapIcon UriSource="ms-appx:///Icons/report-card.png" />
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem
Content="Schedule exam"
Tag="ManageClassPage">
<NavigationViewItem.Icon>
<BitmapIcon UriSource="ms-appx:///Icons/Schedule.png" />
</NavigationViewItem.Icon>
</NavigationViewItem>
</NavigationView.MenuItems>
<Frame x:Name="NavFrame" Background="Blue" />
</NavigationView>
</Window>
my dependency injection
public partial class App : Application {
private IHost _host;
public App() {
InitializeComponent();
}
protected override void OnLaunched(LaunchActivatedEventArgs args) {
_host = Host.CreateDefaultBuilder()
.ConfigureServices(ConfigureServices)
.Build();
// Start the host
_host.Start();
// Resolve and activate the main window using dependency injection
var mainWindow = _host.Services.GetRequiredService<NavWindow>();
mainWindow.Activate();
}
private void ConfigureServices(IServiceCollection services) {
// Register your dependencies here
services.AddTransient<Frame>();
services.AddTransient<NavWindowViewModel>();
services.AddTransient(provider => new NavWindow(provider.GetRequiredService<NavWindowViewModel>()));
// Add other services as needed
}
}
}