1

I've got a problem with a Prism 7.1, desktop WPF application in which I use Navigation to load a view into one region ("Main") and an associated set of tools into a second region ("Tools"). The short version is that I re-did the layout of the Window and Prism now tells me that the "Tools" region is no longer there.

This is the app, basically

-----------------------------------------------------
| "Explore"   |                                     |              
| "Analyze"   |     ("Main" region.  Shows          |
| "Configure" |     whichever view was selected     |
|-------------|     on the top left)                |
| ("Tools"    |                                     |
|  region)    |                                     |
-----------------------------------------------------     

The user clicks a navigation button (e.g. "Analyze", "Configure", etc) and I use Prism navigate the Main region to the appropriate view from the appropriate module. This part still works.

I also have a RegionBehavior that makes the "Tools" navigate to a separate view associated with the main one. (Found this approach in a PluralSight course called "Prism Problems & Solutions: Loading Dependent Views").

This worked fine when I had an ugly layout with a grid with a couple of ContentControls and appropriate region names. But today I tried replacing this with a slick Telerik RadNavigationView. The main view still shows up nicely but the "Tools" view never appears now.

The immediate cause is clear: My RegionBehavior no longer has a "Tools" region in which to put the associated tools view into. The RegionManager says it's not there. Even though I am still clearly putting its name on a ContentControl as before.

But the underlying cause is unclear. There is still a ContentControl with the "Tools" region name. So why is Prism not creating (or adding) that region? Can I force it to?

This is the old XAML that worked:

<Grid Background="{StaticResource GsBackgroundDark}">

    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/> <!-- Navigation/Tools Panel -->
        <ColumnDefinition Width="*"/>    <!-- Page Content Region -->
    </Grid.ColumnDefinitions>

    <!-- Left column has navigation buttons above a Prism region for "tools" -->
    <Grid Grid.Column="0">

        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>  <!-- Navigation Buttons -->
            <RowDefinition Height="*"/>     <!-- Tools Region -->
        </Grid.RowDefinitions>

         <!-- Traditional list of category buttons used to navigate ItemTemplate left out (not relevant) -->
        <ItemsControl ItemsSource="{Binding AvailablePages, IsAsync=True}"/>

        <!-- "Tools" pane Content Control, bottom left-->

        <Grid Grid.Row="1">
            <ContentControl prism:RegionManager.RegionName="Tool"/>
        </Grid>
    </Grid>

    <!-- Main Content on the right.   -->

    <ContentControl Grid.Column="1" Grid.Row="1" prism:RegionManager.RegionName="Main"/>

</Grid>

This is the new RadNavigationView XAML that does not work. (I tried putting the "Tools" section in the PaneFooter element)

<Grid Background="{StaticResource GsBackgroundDark}">


    <tk:RadNavigationView x:Name="GridView"Background="Transparent"
                          ItemsSource="{Binding Items}" SelectedItem="{Binding CurrentItem}">
        <tk:RadNavigationView.Content>
            <ContentControl prism:RegionManager.RegionName="Main"/>
        </tk:RadNavigationView.Content>

        <tk:RadNavigationView.PaneFooter>
           <ContentControl Grid.Column="0" prism:RegionManager.RegionName="Tool" />
        </tk:RadNavigationView.PaneFooter>

    </tk:RadNavigationView>

The remainder of the code (below) has not changed but I'm putting it here so you can see what it does.

The "Main" views specify their associated tool views using an attribute. For example here is "AnalyzeView":

[PageTool(typeof(AnalyzeViewTools))]  // Associate AnalyzeViewTools with this view
public partial class AnalyzeView
    : UserControl
    , IPageView
    , ISupportDataContext
{
    // blah blah blah....
}
public partial class AnalyzeViewTools : UserControl, ISupportDataContext
{
    // blah blah blah...
}

This is the attribute in question:

[AttributeUsage(AttributeTargets.Class, AllowMultiple=true)]
public class PageToolAttribute : Attribute
{
    public Type Type {  get; }
    public PageToolAttribute(Type toolType) { Type = toolType; }
}

And finally, this is the region behavior which I register at app startup time and which does the work of loading the associated tool views. I have noted the line that's now failing with "THIS FAILS NOW"

public class ToolRegionBehavior : RegionBehavior
{
    public const string BehaviorKey = "ToolRegionBehavior";
    protected override void OnAttach()
    {
        // Our behavior monitors the region's ActiveView collection.

        if (Region.Name == Regions.Main)
            Region.ActiveViews.CollectionChanged += Views_CollectionChanged;
    }

    // A view has been added or removed.  Make the tools panel reflect this

    private void Views_CollectionChanged(
        object sender, 
        NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            // For each view now showing (there should be only one), try to
            // find a tools view for it.  If we find one, inject it into the
            // tools region.  Views are not required to have associated Tool Panels. 

            Debug.Assert(e.NewItems.Count == 0 || e.NewItems.Count == 1);

            foreach (var view in e.NewItems)
            {
                var toolList = new List<UserControl>();

                // If this view supports a tools panel, it will have an attribute
                // So... if you want to add a tool panel to a view, you need
                // to specify this same attribute, just as, for example,
                // OldAnalyzeViewPanel does.

                foreach (var atr in GetCustomAttributes<PageToolAttribute>(view.GetType()))
                {
                    var tool = Activator.CreateInstance(atr.Type) as UserControl;    

                    // If the tool indicates that it wants to share the view's
                    // data context, then pass it over. (It indicates this
                    // by supporting an interface.)

                    if (tool is ISupportDataContext toolCtx && view is ISupportDataContext viewCtx)
                        toolCtx.DataContext = viewCtx.DataContext;

                    toolList.Add(tool);
                }

                // ***************************************
                // **** THIS FAILS NOW  NO SUCH REGION ***
                // ***************************************

                if (Region.RegionManager.Regions.ContainsRegionWithName("Tool"))
                    toolList.ForEach(x => Region.RegionManager.Regions["Tool"].Add(x));
            }
        }

        else if (e.Action == NotifyCollectionChangedAction.Remove)
        {
            // A view was removed from the main region.  Remove the
            // corresponding tool view we previously injected, if any.  At
            // most there should be one.

            if (!Region.RegionManager.Regions.ContainsRegionWithName("Tool"))
                return;

            var region      = Region.RegionManager.Regions["Tool"];
            region.Views.ToList().ForEach(x => region.Remove(x));
        }
    }


    // Helper to get attribute off of views

    private static IEnumerable<T> GetCustomAttributes<T>(Type type)
    {
        return type.GetCustomAttributes(typeof(T), true).OfType<T>();
    }

}
Joe
  • 5,394
  • 3
  • 23
  • 54
  • 1
    When is the footer created? If it's not initially there, you have to set the region from code-behind. See https://stackoverflow.com/questions/41212881/region-manager-can-not-find-region-inside-of-the-custom-popupwindow/41228367#41228367 – Haukinger May 29 '19 at 21:59
  • That was it exactly. I just hooked on to the OnLoaded event, set the name and region manager and it worked. I must have gone through about 5 different Prism region searches but I didn't find that question. Thank you. – Joe May 30 '19 at 11:30

0 Answers0