Reputation: 822
I'm new to Prism and trying to make a simple modular app with it (see the full code).
I'm actually trying to pass a parameter to a view, so in the ModuleAViewViewModel
of the ModuleAView
I'm implementing INavigationAware
, this way:
public class ModuleAViewViewModel : BindableBase, INavigationAware
{
private int passedId;
public int PassedId
{
get => passedId;
set => SetProperty(ref passedId, value);
}
// In the following 3 methods, a breakpoint never gets hit.
public bool IsNavigationTarget(NavigationContext navigationContext)
{
return true;
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
PassedId = (int)navigationContext.Parameters["Id"];
}
}
This is the corresponding ModuleAView
.
<UserControl x:Class="ModularSample1.Modules.ModuleA.Views.ModuleAView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ModularSample1.Modules.ModuleA.Views"
xmlns:viewmodels="clr-namespace:ModularSample1.Modules.ModuleA.ViewModels"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<viewmodels:ModuleAViewViewModel x:Key="moduleAViewModel"/>
</UserControl.Resources>
<Grid DataContext="{StaticResource moduleAViewModel}">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock
Grid.Row="1"
Text="{Binding PassedId, StringFormat='Passed Id: {0}'}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="34"/>
</Grid>
</UserControl>
And the ViewModel that actually navigates to that view looks like this:
public class MainWindowViewModel : BindableBase
{
private readonly IRegionManager regionManager;
public MainWindowViewModel(IRegionManager regionManager, IModuleManager moduleManager)
{
this.regionManager = regionManager;
moduleManager.Run();
Modules = moduleManager.Modules.ToList();
}
private List<IModuleInfo> modules;
private IModuleInfo selectedModule;
public List<IModuleInfo> Modules
{
get => modules;
set => SetProperty(ref modules, value);
}
public IModuleInfo SelectedModule
{
get => selectedModule;
set
{
if (SetProperty(ref selectedModule, value))
{
var Id = new Random().Next(1, 12);
var navigationParameters = new NavigationParameters
{
{ "Id", Id }
};
regionManager.RequestNavigate(
"SelectedModuleRegion",
$"{selectedModule.ModuleName}View",
navigationParameters);
}
}
}
}
What I'm missing here?
Upvotes: 1
Views: 527
Reputation: 22119
You define the view model for your ModuleAView
in its Resources
and set it on a child Grid
via reference. Prism looks for the DataContext
on the view itself to call a view model that implements INavigationAware
, not a child control, so it does not find your view model. From the documentation:
During navigation, Prism checks to see whether the view implements the
INavigationAware
interface; if it does, it calls the required methods during navigation. Prism also checks to see whether the object set as the view'sDataContext
implements this interface; if it does, it calls the required methods during navigation.
In order to make it work, set the data context directly on the ModuleAView
and remove it from Grid
.
<UserControl x:Class="ModularSample1.Modules.ModuleA.Views.ModuleAView"
...>
<UserControl.DataContext>
<viewmodels:ModuleAViewViewModel/>
</UserControl.DataContext>
<Grid>
<!-- ...grid definitions. -->
</Grid>
</UserControl>
A better alternative is to remove setting the data context manually completely from your ModuleAView
and register your ModuleAView
directly with ModuleAViewViewModel
. Prism's navigation service will automatically resolve the view model during navigation and assign it as data context.
containerRegistry.RegisterForNavigation<ModuleAView, ModuleAViewViewModel>();
You can even simplify this, by following the naming conventions for views and view models regarding the ViewModelLocator
, which will be used in navigation to resolve view models for views.
.ViewModels
child namespace.Views
child namespaceViewModel.
You violate the last rule, so renaming ModuleAViewViewModel
to ModuleAViewModel
and just removing the manual setting of the data context will enable Prism to automatically find the corresponding view model for the view that you registered with RegisterForNavigation
.
containerRegistry.RegisterForNavigation<ModuleAView>();
Upvotes: 3