导航到模块中的视图时不会调用 OnNavigatedTo
OnNavigatedTo is not invoked when navigating to a view in module
我是 Prism 的新手,正在尝试用它制作一个简单的模块化应用程序(参见 full code)。
我实际上是在尝试将参数传递给视图,所以在 ModuleAView
的 ModuleAViewViewModel
中,我正在实施 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>();
我是 Prism 的新手,正在尝试用它制作一个简单的模块化应用程序(参见 full code)。
我实际上是在尝试将参数传递给视图,所以在 ModuleAView
的 ModuleAViewViewModel
中,我正在实施 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'sDataContext
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>();