简体   繁体   中英

OnNavigatedTo is not invoked when navigating to a view in module

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?

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's DataContext 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 are in the same assembly as the view types
  • ViewModels are in a .ViewModels child namespace
  • Views are in a .Views child namespace
  • ViewModel names correspond with view names and end with " ViewModel.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM