Udostępnij za pośrednictwem


Integrating Prism v4 Region Navigation with Silverlight Frame Navigation

Updated 10/14/2010

This blog post was updated on 10/14/2010 and requires Prism 4 or later.

The code download was updated and the Prismv4FrameRegionNavigation project, FrameRegionNavigationService was updated, adding support for the NavigationFailed and Navigating events.

Updated 2/9/2011

I have published a related blog post that shows how to implement cancelling of the navigation request when using the Silverlight Frame Navigation API that can be read here.

Introduction

This article covers integrating Prism v4 Region Navigation with Silverlight 4 Frame Navigation. Integration is not directly supported by the Prism v4 Library. The included download provides the required classes to integrate the two navigation API's.

The below image pictures the demo application; notice the user friendly, deep link unmapped Uri in the address bar. The right ListBox lists an Item view was opened and subsequently navigated away from.

This included application demonstrates how to integrate Prism Region Navigation with Silverlight Frame Navigation. Additionally, we'll examine implementing Non-Linear Navigation in this configuration.

Prerequisites

A general knowledge of Prism regions, modules, MEF, Silverlight Frame Navigation and the Silverlight UriMapper is required to understand this article and demo application.

Before proceeding, please read the Prism v4 Region Navigation Pipeline article. Information presented in that article will not be repeated here.

Integrating Navigation API's

The demo application includes the Prismv4FrameRegionNavigation assembly. This assembly provides the required classes to integrate the two navigation API's such as a content loader, region adapter, journal, navigation service and region behavior. For the remainder of the article, I'll refer to the Prismv4FrameRegionNavigation assembly as, "the assembly."

 <navigation:Frame 
    x:Name="ContentFrame" 
    Style="{StaticResource ContentFrameStyle}" 
    Source="/HomeView" 
    Navigated="ContentFrame_Navigated" 
    NavigationFailed="ContentFrame_NavigationFailed"
    prism:RegionManager.RegionName="MainContentRegion"
    >

    <navigation:Frame.ContentLoader>
        <prism_Regions:FrameContentLoader RegionName="MainContentRegion"/>
    </navigation:Frame.ContentLoader>

    <navigation:Frame.UriMapper>
        <uriMapper:UriMapper>
                        
         <!--Default applicaiton mapper-->
         <uriMapper:UriMapping Uri="" MappedUri="/ThePhoneCompany.Views.HomeView"/>
                       
         <!--Used to add a new record-->
         <uriMapper:UriMapping Uri="/{moduleName}/{pageName}/add" MappedUri="ThePhoneCompany.{moduleName}.Views.{pageName}?key=0"/>
                        
         <!--Used to edit a record-->
         <uriMapper:UriMapping Uri="/{moduleName}/{pageName}/{key}" MappedUri="ThePhoneCompany.{moduleName}.Views.{pageName}?key={key}"/>

         <!--Used to view a page-->
         <uriMapper:UriMapping Uri="/{moduleName}/{pageName}" MappedUri="ThePhoneCompany.{moduleName}.Views.{pageName}"/>
                        
         <!--Used to navigate to a page in the Shell-->
         <uriMapper:UriMapping Uri="/{pageName}" MappedUri="/ThePhoneCompany.Views.{pageName}"/>

        </uriMapper:UriMapper>
    </navigation:Frame.UriMapper>
</navigation:Frame>

The RegionManager.RegionName attached property is attached to the Frame control. In your past Prism projects you probably added this attached property to a ContentControl, ItemsControl or TabControl. The assembly provides the region adapter and behavior which enables the Prism Region to be attached to the Frame control.

The included FrameContentLoader is used in the above XAML snippet. This content loader is a replacement for the default Silverlight ContentLoader. Notice the required RegionName property on the FrameContentLoader that matches the RegionName in the Frame RegionManager.RegionName attached property.

The assembly classes route all Region Navigation API requests to the Frame. This was done so that all navigation requests, regardless of origin, are processed uniformly by the Frame. This also ensures that the Frame's UriMapper can handle mapping user friendly Uri's to application MappedUri's.

A glance at the above UriMappings shows that this scheme supports multiple modules that can use the same UriMappings.

By default, the Region Navigation API's use an object's short type name to look it up in the container for creation and when iterating a region's contents to determine if the object can handle the navigation request.

I have elected to use full type names to identify objects in the container for navigation purposes. I also did this in the Prism v4 Region Navigation Pipeline demo application.

The ThePhoneCompany.Infrastructure.FullTypeNameRegionNavigationContentLoader class is used to change the default strategy from short type names to full type names, for determining which objects in the region are candidates to be checked if they are the navigation target. This the same class used in the Prism v4 Region Navigation Pipeline demo application.

User friendly Uri's are not only used in the address bar, but also by the application RequestNavigate method calls.  The below code snippet shows the CategoryViewModel CloseExecute method, calling RequestNavigate from code.  The InventoryHomeView string constant keeps the magic strings out of the code.

 public const String InventoryHomeView = "/Inventory/InventoryView";

void CloseExecute() {
    _keepAlive = false;
    _regionManager.RequestNavigate(RegionNames.MainContentRegion, Constants.InventoryHomeView);
}

Using friendly Uri’s also allows HyperlinkButtons to initiate navigation without additional code other than setting the NavigateUri property in XAML. In the below XAML snippet from the  InventoryView.xaml ListBox DataTemplate.  You can see how simple it is to data bind the ItemID property to set the NavigateUri property.

 <DataTemplate>
    <Grid Loaded="lbDataItemsGridItemTemplate_Loaded">

      ...
      
      <HyperlinkButton 
        Grid.Column="3" Margin="7,0,0,0" Content="edit" 
        NavigateUri="{Binding Path=ItemID, StringFormat=/Inventory/ItemView/\{0\}}" />
    </Grid>
</DataTemplate>

In-fact all but two navigation requests are initiated in XAML and not code. The two RequestNavigate method calls are in the ItemViewModel and CategoryViewModel CloseExecute methods.

Errors that are thrown during navigation requests will be bubbled up to the Frame and the Frame will raise the NavigationFailed event.

In addition to address bar deep linking and the Frame handling navigation errors, navigating against a Frame from XAML is a very good benefit of this implementation.

Developers can modify the Prismv4FrameRegionNavigation assembly's classes to meet the specific needs of their applications.

Lessons Learned

Assembly Loading on Application Start Up

In Silverlight, Prism Modules can be created using one of the Visual Studio Silverlight Applications project templates or a Silverlight Class Library project template.

The reason you use one of the Silverlight Application project templates is for packing. When the Silverlight Application is compiled, it will be packed in its own XAP. Packaging the assembly in its own XAP provides the developer a number of options for when the XAP is actually downloaded and loaded into the Silverlight application domain. If your Silverlight application consists of several XAPs, your initial load time can be decreased, since you will only have to get the XAP that contains the shell download and display the shell.

The reason you use the Silverlight Class Library project template is to provide code separation and promote reuse across solutions. Another reason to use this project template type is to package the assembly with the main Silverlight application; in other words, this assembly will be part of the Silverlight application's XAP.

So, what does this have to do with start up?

The Navigation API's require that the container can create the target object. Meaning, if you are using MEF or an IOC container, the Navigation API will call into the container requesting the target object by name. If the container can't create the object, the container will throw and the navigation request will stop.

If your solution is packaged in several XAPs, and the target of the navigation is in a XAP that has not been downloaded or is in the process of downloading, the container will throw an exception when the target object is requested.

Now let's look at two real-world scenarios that could cause a problem.

Please note, these issues are not caused by using the Navigation API, but are a side-effect of the asynchronous downloading of assemblies and the timing of accessing those assemblies before they are loaded and ready for use.

  • Deep linking – the user opens their browser; enters a deep link Url and presses enter. If your application is broken down into multiple XAPs and the target of the deep link is not in the Silverlight application XAP it is possible that the user will get an error because the target XAP has not yet been downloaded.
  • Main application attempts to navigate to a target that has not yet been loaded – this can happen even if your application is not navigating using a deep link. The main application has loaded and contains a button that navigates to class in module that is still loading. If the user clicks that button, an error will occur because the target is still loading.

To solve these problems you can: 

  • Package your assemblies in the main Silverlight application XAP.

  • Intercept the navigation request, verify the assembly is loaded then proceed with the navigation request. If the assembly is not loaded or is in the process of loading, you can wait until the assembly loads, and then proceed with the request.

    • MEF Catalogs have a Changed event that you can hook to determine the status of assembly loading.

Silverlight Applications and MEF

There is a known issue when referencing the Prism MefExtensions assembly from multiple Silverlight assemblies. Your main Silverlight application should reference the assembly and set Copy Local to True.

All other assemblies that reference the Prism MefExtensions assembly must set Copy Local to False as pictured below.

If you forget to change the Copy Local property value to False, an exception will be thrown during the bootstrapping process. However, the message will indicate that you need to set Copy Local to False.

Non-Linear Navigation Implementation

In addition to Region Navigation integration, this application implements Non-Linear Navigation features similar to the Prism v4 Region Navigation Pipeline demo application.

This application demonstrates using the metadata by surfacing it in four locations as pictured below.

The Application metadata property is used to aggregate the count of the views in the region from the Inventory module. See the top inventory-(3) button text.  Each time the Frame is navigated the Navigated event is raised and this event handler is invoked.

 void ContentFrame_Navigated(Object sender, System.Windows.Navigation.NavigationEventArgs e) {

. . .
    //Posting to the dispatcher because the remove item from region does not get executed before this gets called.
    //Delaying the execution by posting this, enables the Inventory Hyperlink button to have the correct count displayed.
    this.Dispatcher.BeginInvoke((Action)delegate {
        this.hlbInventory.Content = MakeLabelWithCountForApplicationSuite(Constants.Inventory, Constants.Inventory.ToLower());
    });
}

The below method is called from the above code and returns a formatted string that will be used as the Hyperlink’s content.

 String MakeLabelWithCountForApplicationSuite(String applicaitonName, String labelText) {
    Int32 count = 0;

    foreach (var item in this.RegionManager.Regions[RegionNames.MainContentRegion].Views) {
        var fwe = item as FrameworkElement;
        if (fwe != null) {
            var nonLinearNavigationObject = fwe.DataContext as INonLinearNavigationObject;
            if (nonLinearNavigationObject != null && nonLinearNavigationObject.Application == applicaitonName) {
                count += 1;
            }
        }
    }

    if (count == 0)
        return labelText;
    else
        return String.Format("{0}-({1})", labelText, count);
}

The InventoryViewModel creates the text for two inventory function buttons, Item-(1) and Category-(2), see in the above screen shot. This is accomplished by matching the types in the region with the type that each of the button provides selection for.

 String MakeLabelWithCountForApplicationView(Type viewType, String labelText) {
    Int32 count = 0;

    foreach(var item in _regionManager.Regions[RegionNames.MainContentRegion].Views) {
        if(item.GetType() == viewType) {
            count += 1;
        }
    }

    if(count == 0)
        return labelText;
    else
        return String.Format("{0}-({1})", labelText, count);
}

The open items for the selected inventory function are listed in the right side ListBox. This information comes from the region views metadata.  The below code snippet  checks which inventory function is active, then iterates over the views in the region looking for matching types; when found adds the metadata to the list for display in the right side ListBox.

 void UpdateActiveDataItems() {
    try {
        if(ItemIsChecked)
            ActiveDataItems.Source = this.GetActiveDataItems(typeof(ItemView));
        else if(CategoryIsChecked)
            ActiveDataItems.Source = this.GetActiveDataItems(typeof(CategoryView));
    } catch(Exception) { }
}

IList<NonLinearNavigationMetadata> GetActiveDataItems(Type viewType) {
    var list = new List<NonLinearNavigationMetadata>();
    foreach(var item in _regionManager.Regions[RegionNames.MainContentRegion].Views) {
        if(item.GetType() == viewType) {
            var fwe = item as FrameworkElement;
            if(fwe != null) {
                var nonLinearNavigationObject = fwe.DataContext as INonLinearNavigationObject;
                if(nonLinearNavigationObject != null) {
                    list.Add(new NonLinearNavigationMetadata(nonLinearNavigationObject));
                }
            }
        }
    }
    return list;
}

As you can see, metadata is at the heart of implementing Non-Linear Navigation. Surfacing the metadata in creative ways makes it very easy for end users to use your software applications.

Video

The demo application video can be viewed here.

Note: You can view the high resolution version of the .wmv video file by:

  • Clicking on the video link
  • Log into Vimeo

After logging in, you'll be given access to the high resolution video download. There is no cost associated with this.

Download and Video

The link to download the demo application is located at the bottom of this article.

Requirements: you must download Prism 4 or later and run the RegisterPrismBinaries.bat batch file. The Prism v4 Readme covers this file in detail. If you do not want to run this batch file, you'll need to remove and re-add the references to the Prism assemblies.

Comments

Microsoft values your opinion about our products, guidance, documentation and samples.

Thank you for your feedback and have a great day,

Karl Shifflett

Patterns & Practices Prism Team

SilverlightPrismv4IntegratedNavigationUpdated-10-14-2010.zip

Comments

  • Anonymous
    October 08, 2010
    Great work! Can you tell me how I can make this work with nested frame regions? For example, I have 2 frames: OuterFrame and InnerFrame. How can I make a deep link load OuterView2 and InnerView5 in their respective frames? In my app, my Shell has a MasterRegion where I first load my LoginView and RegistrationView. After the user logs in, I replace the LoginView with a LayoutView. My LayoutView contains several regions that switch between views.

  • Anonymous
    October 08, 2010
    Great work! Can you tell me how I can make this work with nested frame regions? For example, I have 2 frames: OuterFrame and InnerFrame. How can I make a deep link load OuterView2 and InnerView5 in their respective frames? In my app, my Shell has a MasterRegion where I first load my LoginView and RegistrationView. After the user logs in, I replace the LoginView with a LayoutView. My LayoutView contains several regions that switch between views.

  • Anonymous
    October 12, 2010
    Hi Russell, Sorry for the delayed response, I've been out of town. You have several options.

  1.  If the top level Uri contains the information necessary for the inner frame to navigate, your parent form can parse the top level Uri, then initiate a second navigation on the InnerFrame.
  2.  If the top level Uri does not contain the information necessary for the inner frame to navigate, your parent form can simply initiate a second navigation on the InnerFrame to a default Uri or possibly the last location, provided you store that information. Does this help? Cheers, Karl
  • Anonymous
    October 15, 2010
    It turns out that option 1 is how I ended up solving my situation. Thanks for the reply, though. At least I know there isn't a more elegant way of implementing my scenario.

  • Anonymous
    October 18, 2010
    Hi Karl, I've been trying out this sample and would like to use it for our upcoming Silverlight project. However, we got stuck when trying to load xap files dynamically. Can this project be modified to do that? We're having troubles in getting the module to download and run on this project. Any help or guidance would be extremely useful. Thanks again Karl!

  • Anonymous
    October 19, 2010
    Derek, Yes, you can modify the project to download xap files dynamically.  Currently, the implementation expects the target of the navigation to be available in the container when you navigate. You can implement a check to see if MEF or your IOC container has the target, if not, download the correct XAP and initiate the navigation.   Basically, you'll add your check in the navigation pipeline.  Remember, users can initiate navigate using deeplinking or a UI elment on a form.   If you can figure this out, please post a message on the Prism Discussion page on CodePlex and we'll help you out. Cheers, Karl

  • Anonymous
    October 21, 2010
    Hi Karl, This is great stuff, thanks for the post. I’ve run in to a small problem with the browser integration when trying to veto a navigation request. Normally the pipeline is paused until the continuationCallback(bool) is called. However, when using the Frame region this doesn’t appear to be the case. In my example I’ve added an InteractionRequest in to the Page stub (FrameNavigationWrapperPage.xaml) and set the Page.DataContext = view.datacontext. My base view model has the following implementation of IConfirmNavigationRequest Which works correctly when the region is a ContentControl (i.e. not using the Frame adapter etc)        void IConfirmNavigationRequest.ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)        {            //ask user if they want to save?            if (IsDirty)            {                _cancelNavigationRequestConfirmation = new InteractionRequest<Confirmation>();                _cancelNavigationRequestConfirmation.Raise(                        new Confirmation { Content = LocalResources.Nav_UnsavedChangesPrompt, Title = AppStrings.Dialog_ConfirmationLabel},                        c => { continuationCallback(c.Confirmed); });            }            else            {                //Default                continuationCallback(true);            }        } I’m Looking at the  “protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)” for a potential fix at the moment. Just wondering if you had any thoughts/potential solutions?

  • Anonymous
    October 21, 2010
    Chooksii, I'll look at this on Monday, 25 Nov and reply back.  I'll run a test and verify it works or is not working. For now, have you tried returning continuationCallback(false); without the interaction request?  This would allow you to nail down where the problem is happening. Cheers, Karl

  • Anonymous
    October 25, 2010
    Chooksii, How have you added an InteractionRequest to the FrameNavigationWrapperPage.xaml?  This UserControl's content is completely replaced during navigation by the FrameContentLoader.cs file.  Meaning that the InteractionRequest XAML wll be removed from the visual tree and can't be executed. Please advise. Karl

  • Anonymous
    October 26, 2010
    The comment has been removed

  • Anonymous
    October 28, 2010
    The comment has been removed

  • Anonymous
    November 04, 2010
    Thanks Karl, Yep, have been using a MessageBox in the meantime. Just wondering if you've had any luck with a workaround? Matt

  • Anonymous
    November 04, 2010
    Matt, Yes, workaround in place.  Will blog it Monday-Tuesday next week when Prism 4 RTM's.  Will update the content of the blog post with answers to other questions as well. Best, Karl

  • Anonymous
    November 04, 2010
    Hi Karl, What about the OnDemand module download feature of Prism... Does this integration deals with that? Thanks! JP

  • Anonymous
    November 04, 2010
    JP, We don't provide code example for this as there are too many scenarios to cover.  Instead we provide the hooks for customers to enable this in their applications. Karl

  • Anonymous
    November 05, 2010
    Thanks Karl, I'm lost in translation... What do you mean by "we provide the hooks"... is there any clue in the source code we can follow, any external guidance? JP

  • Anonymous
    November 05, 2010
    JP, Look at our Modularity QuickStart code and written guidance.  This has an example of loading oni demand. WRT Navigation, this is a much more difficult topic because it all depends on how you implement your navigation.  If you allow a user to navigate to a view that is in an assembly that has not been loaded, the default navigation implementation will fail to locate the view.  In this case you must cancel the navigation, load the assembly and notify the user the asseembly has been loaded and then attempt the navigation operation again. I think the best way to solve this is, have a button that when clicked will load the assembly; while loading, display and animation within the button, then when the assembly is loaded, display the navigation options for the assembly. Cheers, Karl

  • Anonymous
    November 18, 2010
    Hi Karl, We are using Prismv4FrameRegionNavigation on Drop 10 and are having the same bug with inability to veto navigation. Are there any plans on fixing it? /Yuri (zholobov@gmail.com)

  • Anonymous
    November 19, 2010
    Yuri, Please use the latest build of Prism 4 www.microsoft.com/.../details.aspx I'm unavailable until 1 Dec 2010 and will investiage the veto problem. Have a great day, Karl

  • Anonymous
    December 12, 2010
    When navigating to ThePhoneCompanyTestPage.html# Home hyperlink button doesn't highlight. How to fix it?

  • Anonymous
    December 13, 2010
    Andrii What is the: ThePhoneCompanyTestPage.html# I don't have that page in the solution. Karl

  • Anonymous
    December 13, 2010
    The comment has been removed

  • Anonymous
    December 14, 2010
    Ben, Yes, I have it working.  I'm looking into Silverlight modal dialog implementations beside MessageBox and will post the code soon. Karl

  • Anonymous
    December 16, 2010
    The comment has been removed

  • Anonymous
    December 16, 2010
    Ben, Its going up today. Karl

  • Anonymous
    December 16, 2010
    Hi Karl, Thank you for the code and video. I have a question. In the VS 2010 solution I noticed that you batch the View, View Code behind and ViewModel class under one file. I wonder how can you achieve that in Visual Studio 2010 because the usual approach is to have your Views folder and your VeiwModels folder. I know that this will have nothing to do with the functionality because you have to Import the ViewModel to the View regardless of the file location but it looks really nice and handy. Regards, Sul

  • Anonymous
    December 16, 2010
    Sul, Check out this VS Extension:  visualstudiogallery.msdn.microsoft.com/.../9d6ef0ce-2bef-4a82-9a84-7718caa5bb45 Cheers, Karl

  • Anonymous
    December 19, 2010
    Hi Karl That's great news. Please can you provide a link? Thanks Ben

  • Anonymous
    December 30, 2010
    Ben, I will post this later today or Friday.  Sorry for the delay.  I need to finish up the blog post. Karl

  • Anonymous
    January 03, 2011
    I have a prism based app and am not sure how to it use ur sample to implement deep linking. I have a shellview which has 3 regions- the intial view shows a list  and once user selects one of items in the list, it shows shrinks the listbox to 1/4 of the entire space and shows one region @ top and other to right of the list. User can click another item on list and data changes get reflected in the other regions. Can you please guide me how to implement deep linking?

  • Anonymous
    January 05, 2011
    Hi, I'd like to point out a mistake I made. I forgot to override ConfigureRegionAdapterMappings() in the Bootstrapper. The result was quite a cryptic exception during ContentFrame loading: The content loaded was of type System.Windows.Controls.Frame, which is not a subclass of System.Windows.Controls.UserControl. As soon as I properly specify RegionAdapterMappings, the error is gone and navigation works perfectly.

  • Anonymous
    January 05, 2011
    Jane, The attached example does deeplinking.  If you have nested regions, when the parent region gets navigated to, then you'll need to navigate any sub regions.  In the parents OnNavigatedTo method, parse the Url for sub region parameters and then take action to navigate the sub region. Have a great day, Karl

  • Anonymous
    January 05, 2011
    Lukas Cenovsky, Glad you sorted out the issue. Best, Karl

  • Anonymous
    February 02, 2011
    Hmm, i can't figure out my mistake, I'm using your library for the navigation in my prism application, but instead of the page I have a system.Object displayed. Anyone had this issue ?

  • Anonymous
    February 04, 2011
    Faress, Not sure why you are having this.  Can you post your project somewhere and post a link? Karl

  • Anonymous
    February 04, 2011
    Hi Karl, Did you get a chance to post the workaround for the Veto issue? Cheers, Matt

  • Anonymous
    February 08, 2011
    Matt, So sorry I have not posted this.  I'll post the solution today. Karl

  • Anonymous
    February 14, 2011
    I'm having a hard time making this work with prism, anyone achieved this with prism ?

  • Anonymous
    February 21, 2011
    faress What problem are you having?  This uses Prism. Karl

  • Anonymous
    February 21, 2011
    Posted update to this post here:  blogs.msdn.com/.../cancelling-a-navigation-request-using-prism-v4-region-navigation-with-silverlight-frame-navigation.aspx

  • Anonymous
    March 02, 2011
    Hi Karl, I'm really interested in the prism silverlight concept. I'm just wondering if prism, mainly the navigation api, is possible within a silverlight application that is running out of browser? I'm hoping to develop a silverlight business application that runs out of browser using the prism navigation frames to cut down my xaml. Prism navigation should also allow me to re-use my silverlight user controls and allow me to do the main bulk of my development within the visual studio environment rather than expression blend. Currently I have numerous states within blend for my silverlight app pages which is becoming a messy affair, prism navigation reads like a great fix for this as long as it can be used out of browser? Thanks.

  • Anonymous
    March 04, 2011
    For the sake of all that is good, people.  If you create a tutorial that uses a custom attached property, PLEASE include the XMLNS in your code snippets.

  • Anonymous
    March 07, 2011
    aspnet-scotland, Yes, Prism Navigation works in out of browser applications. Karl

  • Anonymous
    March 08, 2011
    Hi Karl, In your post you mention: "The included FrameContentLoader is used in the above XAML snippet. This content loader is a replacement for the default Silverlight ContentLoader.". Could you ellaborate on this? Why have you done this and what you have done? Many thanks,

  • Anonymous
    March 09, 2011
    Carl, The custom content loader is a bridge between the Prism Navigation API's and the Silverlight Frame Navigation API.   This bridge forwards all Prism Navigation calls to the Silverlight Frame Navigation API while at the same time enabling the Prism Navigation API to work the same as other applicaiton that are not using the Silveright Navigation API. Best, Karl

  • Anonymous
    March 09, 2011
    Karl, Thank you for the reponse. This example is using MEF, have you tried this with Unity? I am trying to fit this in to an existing project which uses Unity. Any pointers would be greatly appreciated. Thanks again,

  • Anonymous
    March 10, 2011
    Carl, I just posted a Unity sample project here:  blogs.msdn.com/.../prism-4-region-navigation-with-silverlight-frame-navigation-and-unity.aspx Best to you, Karl

  • Anonymous
    March 31, 2011
    Nice Work Karl ! I had a few problems getting the navigation setup, so I though I would post this in case it could help others... I kept getting this error in the BeginLoad event of the FrameContentLoader: Cannot create navigation target 'MIS-Maps.Views.HomeView' This was the URImapping I had in place: <navigation:Frame x:Name="ContentFrame"                              Style="{StaticResource ContentFrameStyle}"                              Source="/HomeView"                              prism:RegionManager.RegionName="MainContentRegion"                              Navigated="ContentFrameNavigated"                              NavigationFailed="ContentFrameNavigationFailed"> .... Other Code ..... <!--Used to navigate to a page in the Shell-->                        <uriMapper:UriMapping Uri="/{pageName}"                                              MappedUri="/MIS_Maps.Views.{pageName}" /> Gotcha # 1 is to make sure that there is NO preceding '/' in front of your MappedURI attribute... <!--Used to navigate to a page in the Shell-->                        <uriMapper:UriMapping Uri="/{pageName}"                                              MappedUri="MIS_Maps.Views.{pageName}" /> Gotcha # 2 is If you are using MEF & you are exporting the type via interface then the URI needs to be the the namespace and name of the interface correct ? namespace MIS_Maps.Views [Export(typeof(IHomeView))] public partial class HomeView : ViewModelBase , IHomeView So that this is the correct hyperlink for the 'Source' property above: HomeView needs to be the name of the Interface that I export the HomeView type as which happens to be IHomeView <navigation:Frame x:Name="ContentFrame"                              Style="{StaticResource ContentFrameStyle}"                              Source="/IHomeView"                              prism:RegionManager.RegionName="MainContentRegion"                              Navigated="ContentFrameNavigated"                              NavigationFailed="ContentFrameNavigationFailed"> Thanks Greg

  • Anonymous
    April 04, 2011
    Faress, if you are using Unity in your Prism app check out compositewpf.codeplex.com/.../7383 for a solution to the System.Object problem.

  • Anonymous
    April 04, 2011
    Greg, You had problems because the you must navigate to the same name that you loaded into MEF. This is why I use the full type name when registering types with MEF or Unity and always navigate using the full type name. Then the issues you bring up won't be a problem.. Karl

  • Anonymous
    April 15, 2011
    Hi Karl, What is the approach if I need to load more than one view in the region when I click on the menu item? Dragan

  • Anonymous
    April 15, 2011
    Dragan, Not sure I fully understand your question.   You can navigate to a region that has sub regions or a region that has multiple UserControls.  Either of these should handle your requirements. Karl

  • Anonymous
    April 18, 2011
    I have a basic implementation using this framework and it is working well.  However, it appears that the sync of navigation events is only one way.  If I start navigation from RegionNavigationService.RequestNavigation() then navigation happens correctly and the RegionNavigationService.Navigated event is called.  When I start navigation from a hyperlink or updating the url in the browser the navigation happens correctly but the RegionNavigationSevice.Navigated event is not called.  Is this a known limitation and/or is there a good way to hook this up correctly. Thanks, Chad

  • Anonymous
    April 18, 2011
    Chad, I'll look into this.  Thank you for reporting this. Karl

  • Anonymous
    April 25, 2011
    Great work! I would like to remove some of my views and make them eligible for garbage collection when I navigate away from them. I have tried to implement the IRegionMemberLifetime interface and return “false” for the the KeepAlive property, but it does not seem to help. Any ideas on how I can achieve this? Thanks, Andreas

  • Anonymous
    April 27, 2011
    Andreas, Please post your question and code here:  compositewpf.codeplex.com/discussions I've never had a problem with IRegionMemberLifetime.  The Prism support team and help you to get your issued resolved quickly. Karl

  • Anonymous
    May 10, 2011
    Hi Karl, I hope this post finds you all well. I am using Silverlight 4 + PRISM v4 + Unity I am trying to use your Prismv4FrameRegionNavigation in my Silverlight 4 project but I am having some issues. I have only one module in my app - CodeGeneratorModule - and I created it as a Silverlight Application project. I am not sure if this is causing the problem since it is not packaged in the main Silverlight application XAP. When I run the application I get no errors but nothing is displayed in the shell. Well I get System.Object even though I am using the right way to register the types in the containder as per  you article. You said  " Intercept the navigation request, verify the assembly is loaded then proceed with the navigation request. If the assembly is not loaded or is in the process of loading, you can wait until the assembly loads, and then proceed with the request. " Please could you provide some sample code of how to do that since I am not sure how and where to write this code. Would I intercept the navigation in the OnNavigatedTo(NavigationContext navigationContext) of the view model? Cheers Please see some code below: ViewModel public class CodeGenViewViewModel : ViewModelBase, INavigationAware, IRegionMemberLifetime, IPageTitle    {        readonly IRegionManager _regionManager;        public CodeGenViewViewModel(IRegionManager regionManager)        {           _regionManager = regionManager;        }        public bool IsNavigationTarget(NavigationContext navigationContext)        {            return true;        }        public void OnNavigatedFrom(NavigationContext navigationContext)        {        }        public void OnNavigatedTo(NavigationContext navigationContext)        {            var test = 1;        }        String IPageTitle.PageTitle        {            get { return "Code Generator"; }        }        void CloseExecute()        {            _keepAlive = true;            //_regionManager.RequestNavigate(RegionNames.MainContentRegion, "regionNAme");        }        Boolean _keepAlive = true;        Boolean IRegionMemberLifetime.KeepAlive        {            get { return _keepAlive; }        }    } This is how I register my ViewModel and View public ModuleInit(IUnityContainer container) {            container                .RegisterType<CodeGenViewViewModel>()                .RegisterType<Object, CodeGenView>(typeof(CodeGenView).FullName); } In my BootStrapper I have tried both approaches below to create/configure the Catalog. However I would prefer using the CreateFromXaml since I do not want to have a reference to the module in my main Silverlight project. protected override IModuleCatalog CreateModuleCatalog() {            return Microsoft.Practices.Prism.Modularity.ModuleCatalog.CreateFromXaml(new Uri("/CodeGenerator;component/ModuleCatalog.xaml", UriKind.Relative)); or protected override void ConfigureModuleCatalog()        {            var moduleInitModuleType = typeof(ModuleInit);            this.ModuleCatalog.AddModule(                new ModuleInfo                {                    ModuleName = moduleInitModuleType.Name,                    ModuleType = moduleInitModuleType.AssemblyQualifiedName,                    InitializationMode = InitializationMode.WhenAvailable,                });        } } This is my Shell.xaml <Border Style="{StaticResource ContentBorderStyle}" Grid.Row="1">                <navigation:Frame                x:Name="ContentFrame"                Style="{StaticResource ContentFrameStyle}"                Source="/CodeGeneratorModule/CodeGenView"                Navigated="ContentFrame_Navigated"                NavigationFailed="ContentFrame_NavigationFailed"                prism:RegionManager.RegionName="MainContentRegion"                >                    <navigation:Frame.ContentLoader>                        <prism_Regions:FrameContentLoader RegionName="MainContentRegion"/>                    </navigation:Frame.ContentLoader>                    <navigation:Frame.UriMapper>                        <uriMapper:UriMapper>                            <!--Used to view a page-->                            <uriMapper:UriMapping Uri="/{moduleName}/{pageName}" MappedUri="ThePhoneCompany.{moduleName}.Views.{pageName}"/>                        </uriMapper:UriMapper>                    </navigation:Frame.UriMapper>                </navigation:Frame> </Border>

  • Anonymous
    May 10, 2011
    Claudio, Please post this question at:  compositewpf.codeplex.com/discussions You could have multiple issues.  The Prism support team can help you get up an running quickly. One thing to check what is the full name of the CodeGenView? Karl

  • Anonymous
    May 10, 2011
    Hi Karl, Thanks for your reply. After writing the post above I also wrote a post to codeplex. What did you mean by " check what is the full name of the CodeGenView" ? This is the full name including the namespace   -    CodeGeneratorModule.Views.CodeGenView Do I need to change the anything in the Source or uriMapper?  Source="/CodeGeneratorModule/CodeGenView" <uriMapper:UriMapping Uri="/{moduleName}/{pageName}" MappedUri="ThePhoneCompany.{moduleName}.Views.{pageName}"/> Also, does your library works with modules that are Silverlight Application project instead of Silverlight Class libraries? Cheers Claudio

  • Anonymous
    May 10, 2011
    Claudio, Yes.  ThePhoneCompany is not your assembly name, correct? Karl

  • Anonymous
    May 11, 2011
    Yep, you are right. I have fixed that but I still have the same problem. In you app you used NavigateUri="/Inventory/InventoryView" However you do not have any modules with Inventory name. Your module name is ThePhoneCompany.Inventory. Could you please explain that to me? This is what I have in my APP: CodeGenerator CodeGenerator.Web CodeGeneratorModule Prismv4FrameRegionNavigation I do not have a dot after my module name like you do. CodeGeneratorModule. Do you think that my NavigateUri and UriMapping are set wrongly? I really would like to get it to work. Also could you please clarify if the library will work with Silverlight application modules instead of Silverlight class libraries You said  " Intercept the navigation request, verify the assembly is loaded then proceed with the navigation request. If the assembly is not loaded or is in the process of loading, you can wait until the assembly loads, and then proceed with the request. " Please could you provide some sample code of how to do that since I am not sure how and where to write this code. Would I intercept the navigation in the OnNavigatedTo(NavigationContext navigationContext) of the view model? Cheers C

  • Anonymous
    May 11, 2011
    Claudio, Please update your question at:  compositewpf.codeplex.com/discussions and work with the team there.  I have to work on another project. If you can't get your answer, please write me back. Karl

  • Anonymous
    May 11, 2011
    Thanks Karl, I will update my question in codeplex

  • Anonymous
    May 19, 2011
    Hi Karl, The guys in codeplex were very helpful. Thanks for this hint. I am reading and re-reading your articles to try and learn more about how the library works. I am also debugging. There is one item that I am still confused about. NavigateKey. Could you please elaborate a bit on how this works and where it gets set? What do I have to do for my pages to have a NavigateKey? Cheers Claudio

  • Anonymous
    May 19, 2011
    Claudio, NavigateKey is from my Ocean framework.  Where did you read about this.  It's not part of Prism. Best, Karl

  • Anonymous
    May 19, 2011
    Karl, well, I am reading all your articles and I came across this in the Navigatus sample. I am finding a bit difficult to figure out how you manage to add the labels with the numbers to show how many items you have edited to the tab, and Item and category labels. I saw a method like this there protected List<NavigateKey> GetActiveDataItems(Type view)        {            var list = new List<NavigateKey>();            if (this.NavigateKey != null)            {                foreach (var item in this.NavigateKey.ActivePages.Pages.Values)                {                    var nk = item.GetValue(NonLinearNavigationContentLoader.NavigateKeyProperty) as NavigateKey;                    if (nk != null && nk.ViewType == view)                    {                        list.Add(nk);                    }                }            }            return list;        } Is this something I should not worry about? Cheers Claudio

  • Anonymous
    May 19, 2011
    Claudio, This does not use Prism.  I recommend using Prism.  I wrote this before I joined patterns & practices.  I also wrote the WPF version of this when I wrote the BBQ Shack.   I recommand Prism because it has many people behind it, as opposed to me, writing a framework and posting on my blog. Best, Karl

  • Anonymous
    May 19, 2011
    ok, thanks for the advice. I will use PRISM :-) So, prism will take of all that for me right? I will concentrate on your PRISM demo then....

  • Anonymous
    May 19, 2011
    Claudio, Prism has a complete, well documented navigation solution for WPF and Silverlight. Best, Karl

  • Anonymous
    May 19, 2011
    Karl, I am a bit confused about how you manage to create the labels and numbers for the tab and item and category labels. Also how you create the edited items list in the Prism demo. Do you have any other article or video I can watch? I have watched your video on vimeo and Silverlight TV. Cheers C

  • Anonymous
    May 19, 2011
    Claudio, For the Inventory tab item header, look at ContentFrame_Navigated in ShellView.xaml.cs.  Each time the frame is navigated, I update the label. The items being edited list is populated in UpdateActiveDataItems  in InventoryViewModel.cs.  This method searches the region for views matching a certain Type, then extracts required information from the views DataContext.  This results in a list of items that the can be displayed in the item currently being edited. Karl

  • Anonymous
    May 19, 2011
    Thanks Karl, I will have a look at those methods. I have noticed that you are using a DataTemplateSelector. Where does the DataItems.View come from? <ListBox Grid.Row="1" Grid.Column="1" x:Name="lbDataItems" ItemsSource="{Binding Path=DataItems.View}" Margin="6"> Cheers Claudio

  • Anonymous
    May 19, 2011
    thanks Karl. I will keep debugging until I get it. Cheers Claudio

  • Anonymous
    May 19, 2011
    Claudio, DataItems is a CollectionViewSource, View is a view of the collection view source.  You can read about it here: msdn.microsoft.com/.../system.windows.data.collectionviewsource.view.aspx Karl

  • Anonymous
    May 19, 2011
    thanks Karl.

  • Anonymous
    June 08, 2011
    Hallo Karl, many thanks for this nice framework. Unfortunately I'm stuck at trying to handle deep links that use caracter casings that differ from my uri mappings. These lead to navigation errors because the right type couldn't be loaded due to the differing caracter casings. But I think it's quite common that people type urls in lower case. Do you have any suggestions how I could solve this? Thanks in advance and regards Holger

  • Anonymous
    June 08, 2011
    Holger, You can override the logic that does the comparison to not perform a case sensitive test.  I'll don't recall the method or syntax, but can consult with the lead developer on Monday and get back to you.  This override is not difficult to perform. Best, Karl

  • Anonymous
    June 08, 2011
    Thanks a lot, I'll also try to find it myself in the mean time. Meanwhile I'm experiencing another weird behaviour: I changed all content xamls from Page to UserControl. When I know run the project I get this navigation error: {System.InvalidOperationException: The content loaded was of type System.Windows.Controls.Frame, which is not a subclass of System.Windows.Controls.UserControl. at System.Windows.Navigation.NavigationService.ContentLoader_BeginLoad_Callback(IAsyncResult result)} If I hit F5 the content shows up as expected and when navigating further the error doesn't show up any more. Why does it try to load a Frame? I already tried to step through the navigation code and what the FrameNavigationWrapperPage is doing but until now I don't reallyhave a clue. Especially why this only happens on the first load and first since I switched to UserControls instead of Pages? Thanks in advance Holger

  • Anonymous
    June 08, 2011
    Holger, Silverlight Frame Navigation uses pages.  Why switch to UserControls? Karl

  • Anonymous
    July 26, 2011
    Views always just added to the collection Region.Views But never removed. This is a memory leak.

  • Anonymous
    July 26, 2011
    vruble, The details views are removed from the Region.Views collection when you close them. Karl