Complex scenario with View-Based Navigation Prism

2019-08-27 21:22发布

问题:

I have a complex scenario with View-Based Navigation using Prism. What I am trying to do, is defining a new NavigationRegion for some modules, in the navitagion region of the parent module.

I'll explain myself:

I have the following projects in my solution:

  • Shell
  • Shell.Module1
  • Shell.Module2
  • Shell.Module3
  • Shell.Module3.SubModule1
  • Shell.Module3.SubModule2

In the shell view, I define the MainNavigationRegion and the MainContentRegion. Module 1 and 2, load the navigation item into the MainNavigationRegion and the View into the MainContentRegion. That is working fine.

The complexity comes with Module3, since Module 3 itself has no functionality. This is this NavigationItemView of the "Shell.Module3" project that is loaded into the MainNavigationRegion:

<Grid HorizontalAlignment="Center">
    <materialDesign:PopupBox x:Name="NavigateToToolsRadioButton" 
    AutomationProperties.AutomationId="ToolsRadioButton" PopupMode="Click" 
    StaysOpen="False" UseLayoutRounding="False" 
    Style="{StaticResource MaterialDesignMultiFloatingActionAccentPopupBox}"  
    PlacementMode="RightAndAlignMiddles">
        <StackPanel Orientation="Horizontal" x:Name="NavigationItemsControl" 
            prism:RegionManager.RegionName="ToolsNavigationRegion">                
        </StackPanel>
    </materialDesign:PopupBox>
</Grid>

In the NavigationItemView of Module3 (that it's loaded in the MainNavigationRegion), I am defining a new NavigationRegion specifically for the submodules of Module 3. However, in the Initialize() method of the Module3.SubModule1 class, I get this error: 'The region manager does not contain the ToolsNavigationRegion region.' This is the method:

public void Initialize()
{
    var navitagionView = Container.Resolve<EarnedValueMethodNavigationItemView>();
    RegionManager.Regions[RegionNames.ToolsNavigationRegion].Add(navitagionView);
    var mainView = Container.Resolve<EarnedValueMethodView>();
    RegionManager.Regions[RegionNames.MainContentRegion].Add(mainView);
}

If I debug RegionManager property, I see that ToolsNavigationRegion is not in there.

If I change this line:

RegionManager.Regions[RegionNames.ToolsNavigationRegion].Add(navitagionView);

by this other line:

RegionManager.Regions[RegionNames.MainNavigationRegion].Add(navitagionView);

then, it works fine, but obviously the navigation item is placed in the Main Navigation Region and I would like to have it under the Navigation Region item of the Parent module. Is it possible what I am trying to accomplish?

EDIT:

I also created the StackPanel RegionAdapter as follows:

public class StackPanelRegionAdapter : RegionAdapterBase<StackPanel>
{
    public StackPanelRegionAdapter(IRegionBehaviorFactory factory)
        : base(factory)
    {

    }

    protected override void Adapt(IRegion region, StackPanel regionTarget)
    {
        region.Views.CollectionChanged += (s, e) =>
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                foreach (FrameworkElement element in e.NewItems)
                {
                    regionTarget.Children.Add(element);
                }
            }

            //implement remove
        };
    }

    protected override IRegion CreateRegion()
    {
        return new AllActiveRegion();
    }
}

回答1:

Expanding on the comment above:

The region manager will find regions marked with the region name attribute by searching the visual tree. If a region is not in the visual tree when the region manager does its search, no region will be created. This is the case for popup windows, for example, that are created on demand.

In that case, the region must be manually assigned during construction of the popup window.

Copied from this answer:

Probably you need to set the region manager manually, in the popup view's code behind (constructor), like this:

RegionManager.SetRegionName( theNameOfTheContentControlInsideThePopup, WellKnownRegionNames.DataFeedRegion );
RegionManager.SetRegionManager( theNameOfTheContentControlInsideThePopup, theRegionManagerInstanceFromUnity );

You'll have to assign a name to the content control hosting the region and somehow acquire the region manager (ServiceLocator.Current.GetInstance<IRegionManager>()).