导航到模块中的视图时不会调用 OnNavigatedTo

OnNavigatedTo is not invoked when navigating to a view in module

我是 Prism 的新手,正在尝试用它制作一个简单的模块化应用程序(参见 full code)。

我实际上是在尝试将参数传递给视图,所以在 ModuleAViewModuleAViewViewModel 中,我正在实施 INavigationAware,这样:

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"];
    }
}

这是对应的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>

实际导航到该视图的 ViewModel 如下所示:

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);
            }
        }
    }
}

我在这里缺少什么?

您在 Resources 中为 ModuleAView 定义了视图模型,并通过引用将其设置在子 Grid 上。 Prism 在视图本身 上寻找 DataContext 来调用实现 INavigationAware 的视图模型,而不是子控件,因此它找不到您的视图模型。来自文档:

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's DataContext implements this interface; if it does, it calls the required methods during navigation.

为了使其工作,直接在 ModuleAView 上设置数据上下文并将其从 Grid 中删除。

<UserControl x:Class="ModularSample1.Modules.ModuleA.Views.ModuleAView"
             ...>
    <UserControl.DataContext>
        <viewmodels:ModuleAViewViewModel/>
    </UserControl.DataContext>
    <Grid>
        <!-- ...grid definitions. -->
    </Grid>
</UserControl>

更好 的替代方法是从您的 ModuleAView 中完全删除手动设置数据上下文,并直接使用 ModuleAViewViewModel 注册您的 ModuleAView。 Prism 的导航服务会在导航过程中自动解析视图模型并将其分配为数据上下文。

containerRegistry.RegisterForNavigation<ModuleAView, ModuleAViewViewModel>();

您甚至可以通过遵循有关 ViewModelLocator 的视图和视图模型的命名约定来简化这一点,这些约定将在导航中用于解析视图的视图模型。

  • ViewModel 与视图类型位于同一程序集中
  • ViewModels 在 .ViewModels 子命名空间中
  • 视图位于 .Views 子命名空间
  • ViewModel 名称与视图名称相对应并以“ViewModel.
  • 结尾

您违反了最后一条规则,因此将 ModuleAViewViewModel 重命名为 ModuleAViewModel 并仅删除数据上下文的手动设置将使 Prism 能够自动为您注册的视图找到相应的视图模型RegisterForNavigation.

containerRegistry.RegisterForNavigation<ModuleAView>();