(X) Hide this
    • Login
    • Join
      • Say No Bots Generate New Image
        By clicking 'Register' you accept the terms of use .

Working with Prism 4 Part 4: Region Navigation

(1 votes)
Brian Noyes
>
Brian Noyes
Joined Jun 10, 2010
Articles:   19
Comments:   117
More Articles
26 comments   /   posted on Feb 16, 2012
Tags:   prism-4 , brian-noyes

This is part 4 in the series Working with Prism 4.

Introduction

At Microsoft ASP.NET Connections March 26- 29 2012 I’ll be presenting a session on Prism development that includes the capabilities covered in this article – the URI-based navigation capabilities of Prism. 

In this article I am going to right some wrongs in the code from the past couple articles that I put there to keep things simple and focused on other things for the first few articles. When using the MVVM pattern, one of the major goals is to maintain loose coupling and separation of concerns between views and their view models. But even more important is that different view models should not be coupled to each other unless it is a parent-child kind of relationship, and view models should not be coupled to other views or their own view either. When I set up the code in the previous article to load and switch CustomerEditView instances and their view models, I did it all from the CustomerListViewModel. That code involved using the Prism RegionManager to do the view loading and switching, but it required me to create instances of CustomerEditView and CustomerEditViewModel in the code of CustomerListViewModel. That is a violation of the decoupling goals of MVVM.

To fix this I am going to leverage one of the other features of Prism 4 – view switching navigation. In the previous articles, you have seen two parts of the API of the RegionManager service. One involved the Add and Activate methods of the IRegionManager interface. These allow you to explicitly add a view to a region and activate (or show) it at the appropriate times. You also saw in the last article that the AddToRegion method simplifies the process of adding a view if it will be the only. However, these approaches require you to have a view instance available to pass to the methods. That means the code that makes those calls is inherently coupled to the view instances. If you also need to initialize some state of the view model at the point where you are adding the views, that means you might also be coupled to the view model class in that same code. This is the code I placed in the CustomerListViewModel that really should not have been there.

The sample code for this article builds on the code from the last article. You can download the completed code from Part 3 here. You can download the completed code for this article here.

View Switching Navigation

In Prism 4 the capability was added to have a more implicit and loosely coupled form of view switching that mimics the URI-based navigation of the web. If you think about what a user is doing when they navigate to a particular page on  a web site by putting in an address, they are not really requesting a specific implementation of a page, they are requesting a named view that is the relative portion of the URI (minus the site address at the root). Through mechanisms like the ASP.NET Routing Service, that URI could map to any kind of implementation behind the scenes, and the requester need not know what or where it is. They just need to know the logical name of the view they are trying to get to in the form of a URI. Additionally, the web addressing scheme allows you to pass additional information as part of the URI, including parameters to be passed to the receiver of the request.

If a view model or other code is going to cause views to switch out in the user interface, it would be nice if that code had the same degree of decoupling from the implementation of the target views as well as a similar logical addressing mechanism. Prism added a great capability that mimics this to load and switch views within a region based on an extension method that was added to the IRegionManager interface, called RequestNavigate. This method has several overloads, but they all take two key parameters: the region name in which you want navigation to happen (similar to the site root address in the web browser analogy) and the logical name of the view you want to navigate to. The caller of the method does not have to know what view type or instance the request for navigation maps to, it just knows there is a logical view out there that is wants to see.

This capability includes more than just the ability to load a view into a region. You can pass parameters to its view or view model as part of the navigation request, and the view or view model can use that information to initialize itself or to refresh its state. The view or view model can participate in the decision of whether to create a whole new view or to reuse one that has been shown before. The view can also participate in deciding if and when the navigation can be completed, so that it could for example prompt the user to save changes or to allow the view switching. I’ll be showing you how to leverage all of this in this article.

Step 1: Export the views by logical name

The first modification to make is to declare the logical name of the view as it will be requested by a piece of code wanting to navigate to it. The way this is done with MEF is by using the [Export] attribute with a contract name. When a view is first requested within a region, Prism will create a new instance of it, add it to the region, and activate it. Subsequent requests to navigate to that view type will either get a new instance or will reuse the existing instance, base on some interfaces I’ll discuss a little later in the article.

The modifications to the views look like this:

   1: [Export("CustomerListView")]
   2: [PartCreationPolicy(CreationPolicy.NonShared)]
   3: public partial class CustomerListView : UserControl
   4: {
   5: ...
   6: }

Notice the association of the logical name with the class. In this case, they happen to be the same. But there is no requirement for them to match. The PartCreationPolicy is required because by default, MEF creates singleton instances of any class it exports unless you change the CreationPolicy to NonShared as shown. This allows us to have multiple instances of the view if desired.

Do the same for the CustomerEditView:

   1: [Export("CustomerEditView")]
   2: [PartCreationPolicy(CreationPolicy.NonShared)]
   3: public partial class CustomerEditView : UserControl
   4: {
   5:     public CustomerEditView()
   6:     {
   7:         InitializeComponent();
   8:     }
   9: }

Step 2: Switch to “View First” construction of the CustomerEditViewModel

In the previous article’s code, the CustomerEditViewModel and CustomerEditView were being constructed and married together by code in the CustomerListViewModel. That is part of what we are trying to fix. It is much easier and better from a development tools perspective (Visual Studio and Blend designers – aka “Blendability”) and code simplicity perspective if the view creates the view model declaratively in the XAML. The CustomerListView and OrdersView were already doing this, but I needed to switch the CustomerEditViewModel so that it is structured the same so that when the view gets constructed (which will happen in the Prism framework with the navigation features we are looking at), the view model is also created and wired up as the view’s DataContext.

   1: <UserControl x:Class="Prism101.Modules.Core.CustomerEditView"
   2:              xmlns:local="clr-namespace:Prism101.Modules.Core"
   3:              ...>
   4:     <UserControl.DataContext>
   5:         <local:CustomerEditViewModel />
   6:     </UserControl.DataContext>
   7: </UserControl>

Step 3: Request navigation to the CustomerListView on initial load

This step is not explicitly required, but just want to show an alternative to the initial adding of the CustomerListView to the main region. In the previous few articles, the Core module’s IModule.Initialize code looked like this:

   1: public void Initialize()
   2: {
   3:     var view = new CustomerListView();
   4:     RegionManager.AddToRegion("MainContent", view);
   5: }

Instead, using the navigation features, we could do this:

   1: public void Initialize()
   2: {
   3:     RegionManager.RequestNavigate("MainContent", "CustomerListView");
   4: }

Not a huge savings there, but at least this code no longer has to be coupled to the CustomerListView type and worry about its instance lifetime. In the next few steps you will see how it can really start to shine in other areas.

Step 4: Remove the view model coupled code

In the last article, I had the following code invoked when the Edit button was pressed in the CustomerListViewModel:

   1: private void OnEditCustomer()
   2: {
   3:     IRegion secondaryContentRegion = RegionManager.Regions["SecondaryContent"];
   4:     bool alreadyExists = false;
   5:     foreach (var view in secondaryContentRegion.Views)
   6:     {
   7:         var custView = view as CustomerEditView;
   8:         var custViewModel = custView.DataContext as CustomerEditViewModel;
   9:         if (custViewModel.Customer == SelectedCustomer)
  10:         {
  11:             secondaryContentRegion.Activate(view);
  12:             alreadyExists = true;
  13:         }
  14:     }
  15:     if (!alreadyExists)
  16:     {
  17:         CustomerEditView editView = new CustomerEditView();
  18:         CustomerEditViewModel viewModel = new CustomerEditViewModel { Customer = SelectedCustomer };
  19:         editView.DataContext = viewModel;
  20:         secondaryContentRegion.Add(editView);
  21:         secondaryContentRegion.Activate(editView);
  22:     }
  23: }

This is the code that not only has coupling to the CustomerEditView and CustomerEditViewModel types, it is also doing instance management of those objects, which is really just wrong. Remove all the code in this method.

Step 5: Request navigation to the CustomerEditView for the right customer

Replace the code that was handling editing with the following code:

   1: private void OnEditCustomer()
   2: {
   3:     var uriQuery = new UriQuery();
   4:     if (SelectedCustomer != null)
   5:     {
   6:         uriQuery.Add("customerId", SelectedCustomer.CustomerID);
   7:     }
   8:  
   9:     var uri = new Uri("CustomerEditView" + uriQuery.ToString(), UriKind.Relative);
  10:  
  11:     RegionManager.RequestNavigate("SecondaryContent", uri);
  12: }

Not only is this code much simpler, you can see that there is no type coupling in there at all. The first part of the method uses a helper object from Prism called UriQuery to formulate a query string with a name of customerId and the value from the selected customer. It then concatenates this with the logical view name it wants to request navigation to, and then calls the RegionManager.RequestNavigate extension method, identifying in which region it wants the view to be shown (SecondaryContent in this case). Could not be simpler, right?

Because SecondaryContent happens to be a tab control, it means that each time navigation happens, it could do one of several things:

  • Add a new tab to the control on every navigation, regardless of what customer is selected
  • Add only one tab and replace its content with the information for the customer identified in the query string (in which case there would not be much point in having a tab control)
  • Add a new tab when the customer identified does not already have an active tab, and if it does just activate it

The last option is the one that will be most intuitive for the user, so that is the one we will go with here. But just realize with the mechanisms I’ll be showing shortly, you could do any of these with the exact same RequestNavigate call.

Step 6: Let the CustomerEditViewModel control its own initialization and instancing

In the code that I stripped out of the CustomerListViewModel, the code was not only managing the instancing of the edit view and view model, it was also initializing the state of the view model by setting the Customer property to the SelectedCustomer. Now that Prism is going to take care of creating the view (and implicitly the view model with the view-first construction), you still need a way to initialize the state of the view model. This can easily be done with an interface defined in Prism called INavigationAware. This interface has three members which allow your view or view model to

  • Known when it has been navigated to and get access to the query string parameters to initialize state
  • Known when it is being navigated away from (to do something like persist its state to a cache, service, or DB)
  • Influence whether the view is the target of the navigation or should be reused for navigating to that view type but with different contents

When RequestNavigate is called for a region, the navigation service that does the handling will check the views that are currently contained by that region. If one matches the URI for the view being requested, it will invoke the IsNavigationTarget method to allow that instance to decide whether it should be activated for the navigation to complete. If the view or view model returns true from that, it will be activated if its URI path matches the one being requested. If it returns false, Prism will create a new instance of the view type and place it in the region and activate it. The method is passed a NavigationContext object that contains the URI and parameters for the request to help guide it in its decision to answer the question “are you the one?”

To accommodate the MVVM pattern but not force you to adopt it, whenever Prism looks for an interface implementation on a view, it also checks to see if the DataContext of the view (which should be the view model if doing MVVM) implements it. This allows you to put the logic that supports the interface only on the view model and leave the view as just the structural definition of the visual aspects of the view.

After IsNavigationTarget is called, if it returns true, then the OnNavigatedTo method is called  with the same NavigationContext object. This is the chance for the view or view model to initialize itself (possibly based on URI parameters).

The implementation of the INavigationAware interface in the CustomerEditViewModel looks like this:

   1: bool INavigationAware.IsNavigationTarget(NavigationContext navigationContext)
   2: {
   3:     string custId = navigationContext.Parameters["customerId"];
   4:     if (!string.IsNullOrWhiteSpace(custId) && Customer != null && Customer.CustomerID == custId)
   5:         return true;
   6:     return false;
   7: }
   8:  
   9: void INavigationAware.OnNavigatedTo(NavigationContext navigationContext)
  10: {
  11:     // Choosing to not refresh the customer every time the view is loaded
  12:     if (Customer != null) return;
  13:     // Initial load - Load customer based on ID passed in
  14:     string custId = navigationContext.Parameters["customerId"];
  15:     if (string.IsNullOrWhiteSpace(custId)) return;
  16:     CustomersDomainContext context = new CustomersDomainContext();
  17:     EntityQuery<Customer> custQuery = context.GetCustomersQuery().Where(c => c.CustomerID == custId);
  18:     context.Load(custQuery, OnCustomerLoadCompleted, null);
  19: }
  20:  
  21: private void OnCustomerLoadCompleted(LoadOperation<Customer> obj)
  22: {
  23:     if (obj.HasError)
  24:     {
  25:         MessageBox.Show("Error loading customer: " + obj.Error.Message);
  26:         obj.MarkErrorAsHandled();
  27:         return;
  28:     }
  29:     Customer = obj.Entities.FirstOrDefault();
  30: }
  31:  
  32: void INavigationAware.OnNavigatedFrom(NavigationContext navigationContext)
  33: {
  34: }

You can see that the logic for IsNavigationTarget checks to see if the query string parameter customerId matches the CustomerID property of the Customer that the view model is managing. If you simply wanted to reuse the view and view model instance and only have one instance of that view type (for containment in a ContentControl for example), you could just hardcode a true return value from the IsNavigationTarget. But in our case we are going to have multiple instances of this view type in a tab control, so we want to use the IsNavigationTarget to drive the logic that if the navigation request is for a customer for which there is already a view, just activate that view. If not, create a new instance of that view type and initialize it based on the customerId.

So the OnNavigatedTo method checks to see if the Customer is already set, this view would not be navigated to unless the IsNavigationTarget had found that the Customer matched the request, so there is no initialization needed (unless you wanted to always refresh the customer data from the back end for example). But if the Customer is null, it is the first time activating this view for a given CustomerId, so the code uses RIA Services to load a Customer from the back end. This approach has the additional advantage that the views are more self-deterministic – instead of requiring some other code to know how to get a Customer and shove the right one into the view, the view (or better yet its view model) knows how to go get the right state based on nothing more than a state identifier of some sort that is placed in the query string. This allows you to move the views around within the app, change who their parent view/view model is, and not have to change anything about how the view gets initialized.

If you are concerned that this pattern will make you make more round trips to the back end, all you need to do is adopt the Repository pattern and have your view models call the repository with their state identifiers, and have the Repository cache the data client side and encapsulate what the cache invalidation scheme is so the views don’t have to worry about it and can just request their current state at any time.

Finally, in this case, we have no logic to perform in the OnNavigatedFrom method so we can just leave that one blank.

Step 7: Let the view decide when navigation happens

There is a very important but subtle point in the way the RequestNavigate method is named. It is a request for something to happen, but it doesn’t say when it should happen or make the implication that navigation will be complete when the method returns. Navigation needs to be a non-blocking request because the view that is currently presented might need to do something (such as prompt the user to save) before allowing the navigation to complete. That is inherently a non-deterministic and potentially long-running block (the user might be distracted tweeting in another window for example). Additionally, a view needs to be able to reject navigation because it may be in the middle of an operation it cannot cancel immediately or you may want to let the user decide whether to dismiss a view for example.

So the RequestNavigate method is a non-blocking asynchronous call. If the caller needs to know when navigation is complete, there is an overload that takes a callback reference that will be invoked by the Prism navigation service once the navigation happens or is rejected. If the view does want to decide if and when navigation should occur, it (or its view model) implements an interface called IConfirmNavigationRequest. This interface has one method, ConfirmNavigationRequest, which is passed a NavigationContext like the INavigationAware methods, and a callback for the method to invoke when it has decided to either allow the view to be deactivated (navigated away from) or to reject the navigation.

In the same application, I chose to demonstrate this by using the IsDirty state of the edit views (the same one that is enabling and disabling Save commands as discussed in the last article). If the view state IsDirty, then the view model will prompt the user with a message box to let them confirm or deny navigation with an OK/Cancel action.

The implementation of this interface is shown below. You can see that is IsDirty is true, it prompts the user. If they press OK, the callback is invoked with a true argument, meaning navigation can proceed. If Cancel, then it gets invoked with false.

   1: void IConfirmNavigationRequest.ConfirmNavigationRequest(NavigationContext navigationContext, 
   2:     Action<bool> continuationCallback)
   3: {
   4:     if (IsDirty)
   5:     {
   6:         string prompt = "The view's state has changed and has not been saved, do you want to allow view switching?";
   7:         var result = MessageBox.Show(prompt,"Confirmation",MessageBoxButton.OKCancel);
   8:         if (result == MessageBoxResult.OK)
   9:         {
  10:             continuationCallback(true);
  11:             return;
  12:         }
  13:         else
  14:         {
  15:             continuationCallback(false);
  16:             return;
  17:         }
  18:     }
  19:     continuationCallback(true);
  20: }

Now the one hitch in the sample application is that because these views are presented in a tab control, the user can click on a tab header at any time and cause view switching to occur and the Prism navigation service would not be involved at all, so your view implementations of the INavigationAware and IConfirmNavigationRequest interfaces would not be called. To intercept and prevent tab switching would require a lot lower interception of events on the tab control. So this mechanism for preventing navigation is better suited for containment in a ContentControl where the user does not have a direct user interface mechanism to cause views to swap. But as long as the changing occurs through the navigation controls you put in place that call RequestNavigate, life will be good.

Summary

In this article, you learned how to leverage the navigation capabilities of Prism in a more loosely coupled and flexible way with the IRegionManager.RequestNavigate method, INavigationAware and IConfirmNavigationRequest interfaces. These capabilities allow you to compose a much more loosely coupled application where no code is explicitly tied to view or view model types. The view models can be designed to operate independently of their containers and the code that causes navigation or view switching to happen does not have to be coupled to what the specific implementation of the view is or how it needs to be initialized. This approach still gives you control over when views are created and added to regions and activated, but puts the control in the hands of the views themselves instead of the code that triggers the navigation.

This capability can also be mixed in with the Silverlight navigation framework as shown in this article by Karl Shifflet.

You can download the completed code for this article here.

About the Author

Brian Noyes is Chief Architect of IDesign, a Microsoft Regional Director, and Silverlight MVP. He is a frequent top rated speaker at conferences worldwide including Microsoft TechEd, DevConnections, VSLive!, DevTeach, and others. Brian worked directly on the Prism team with Microsoft patterns and practices and co-authored the book Developers Guide to Microsoft Prism 4. He is also the author of Developing Applications with Windows Workflow Foundation, Smart Client Deployment with ClickOnce, and Data Binding in Windows Forms 2.0. Brian got started programming as a hobby while flying F-14 Tomcats in the U.S. Navy, later turning his passion for code into his current career. You can contact Brian through his blog at http://briannoyes.net/ or on Twitter @briannoyes.


Subscribe

Comments

  • SefiAbderrahmen

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by SefiAbderrahmen on May 21, 2012 12:15

    Hi Brian,

    in the third part, each edition of an object is directly impacted in the datagrid. But using the navigation, this update is no longer visible only after a refresh. My question is there a way to bring up the change immediately in the datagrid of  mainregion or how to refresh the page by using the navigation?

    (I added the contexte.submit change () to persist and i used the navigation aware but the probleme is not solved!)

    thanks.

  • brian.noyes

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by brian.noyes on May 21, 2012 15:20

    I think the right way to address this would be to use the navigation capabilities (implement IConfirmNavigationRequest) in the main view that you are navigating away from that there might be dirty data in. In that implementation, you could choose whether to prompt the user or possibly just automatically persist the changes before navigating away. That would mean you would have to issue the SubmitChanges call AND wait for the callback to know it is complete before allowing navigation to proceed.

  • SefiAbderrahmen

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by SefiAbderrahmen on May 22, 2012 13:16

    Thanks again. I will implement the IConfirmNavigationRequest and see the result. If no change happens i will try to implement the solution of context sharing ( impleminting the context in anathor shared class, ind inject it like singleton with MEF in all  ViewModel)!

  • SefiAbderrahmen

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by SefiAbderrahmen on May 22, 2012 13:49

    Thanks again. I will implement the IConfirmNavigationRequest and see the result. If no change happens i will try to implement the solution of context sharing ( impleminting the context in anathor shared class, ind inject it like singleton with MEF in all  ViewModel)!

  • algodfried

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by algodfried on Jul 25, 2012 19:30

    I am planning on porting an MS Access/SQL Server application to Silverlight using Prism, MEF,  and MVVM. I would like to emulate the UI functionality as closely as possible.

    The UI would be structured as follows:

    1. The shell would contain two regions: NavigationRegion and MainRegion
      1. NavigationRegion would consist of PBs to navigate to views in TabItems in the MainRegion TabControl.
    2. Each view would be contained within its own OnDemand module.
    3. Each view would have a DataGrid and a Detail Form working as Master/Detail.

    My question is, is it possible to configure each Master/Detail view to use Prism navigation using a region in the view as the target for the Detail Form?  If so, would this be better than simply using commands to synchronize the Detail Form to the selected item in the DataGrid?

     

  • brian.noyes

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by brian.noyes on Jul 25, 2012 21:36

    Hi algodfried,

    Unfortunately the short answer is - possibly not without a great deal of complexity. Regions work well for top level navigation and plugging in of views like you describe. They actually support having regions N-levels deep (View A contains Region B into which you plug View C which contains Region D into which you plug View E, etc). The only problem is that regions have to be unique. So as soon as you have two instances of the same parent view that contains a region alive at the same time - typically in two tabs within the UI, regions break. 


    So if each of the parent views you will plug into your MainRegion that is a TabControl are unique with their own child Regions that have different Region names from all the other top level views being plugged in, you will be fine. But for example if you were going to plug in MasterDetailViewA and MasterDetailViewB and they both had two child regions called MasterRegion and DetailsRegion, you are in trouble.

    It is possible to support this, but it requires creating scoped dependency injection containers so that there is a separate RegionManager per tab and down you slide on the slope of complexity.

    Generally I stick to using Regions to plug in and navigate between my top level views, occasionally to swap content in some child region in a view I know there will only ever be one instance of, but otherwise I use MVVM composition (parent-child view model relationships) to handle child view navigation.

    Brian

  • algodfried

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by algodfried on Jul 25, 2012 22:38

    Brian,

    Thanks for the quick response.  My intent is that each parent view plugged into the MainRegion will only occur once. For example, there will never be two Agents tabs.  Any operation concerning Agents will always take place on a single tab.  Based on this, it seems like the region navigation approach will work, but it still might not be the most effective way of implementing the functionality.  If instead I use parent-child view model relationships, can I take advantage of some form of navigation awareness so that I can make sure that records are saved before navigation to a new record?

  • brian.noyes

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by brian.noyes on Jul 25, 2012 22:55

    As long as the tab content views are unique, and don't use overly general terms for their child regions, it will work fine. And there is not really any inefficiency in doing so, in fact it adds consistency to the way navigation happens within the app and remains very loosely coupled.

    With MVVM, it is more of a pattern-based approach where you expose a property or properties from a parent view model that exposes an instance or collection of child view models. You then have a data bound control in the parent view such as a ContentControl (for single reference property) or ItemsControl (for collection property) bound to those view model properties, and use DataTemplates to render the appropriate view for the view model. So navigation happens by changing the parent property references or collection contents.

  • algodfried

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by algodfried on Jul 25, 2012 23:20

    Thanks Brian,

    I think I'll try the Prism navigation to regions implementation and see how it goes.

  • algodfried

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by algodfried on Jul 27, 2012 21:59

    Brian,

    If I navigate directly to a child region before the top level region is navigated to, will the top level module automatically load to expose the top level region so the navigation to the child region can occur?

  • brian.noyes

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by brian.noyes on Jul 28, 2012 21:01

    For that scenario you should use the RegisterViewWithRegion way of associating the child view with the region in the parent. If the parent is not currently being shown, then once it is created the child view will be created (if using the overload with a type for the view) or the factory method will be invoked (separate overload). The other variants of region navigation require the region container control to already be in existence when you ask for navigation.

  • BenMurray

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by BenMurray on Aug 07, 2012 17:44

    Are you planning to do any more tutorials in this series?

  • brian.noyes

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by brian.noyes on Aug 07, 2012 18:57

    Nothing else currently planned. If you have something you think would be of general appeal, feel free to suggest. My publishing calendar is booked up for the next couple months, but could try to work something in after that.

  • psaxton2012

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by psaxton2012 on Aug 15, 2012 09:52

    Hi Brian

    I am trying to use your approach of splitting controls into a seperate class library.

    I want to put the login control onto another control.  The login control is currently inside the silverlight client

     When I try to add this using the tool box I get the error below

     Error Dialog
    -Cannot create an instance of "LoginForm".

    "Cannot find a Resource with the Name/Key ApplicationResources [Line: 19 Position: 65]"

    Any ideas please?  I have tried to copy app.xaml etc into the control's project which does seem like a hack and I still get this?

    Paul

  • brian.noyes

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by brian.noyes on Aug 15, 2012 13:13

    LoginForm? Are you mixing this article up with my RIA Services Authentication and Authorization article?

    Hard to know what the problem is when I have no context of what you did or why.

  • psaxton2012

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by psaxton2012 on Aug 15, 2012 15:23

    Hi Brian

    Yeah I am trying to get RIA services working together with Prism

    Ideally I want to have controls inside a controls library and only complete views in the web host project

    Moving the login control out of the web project and into the controls library works compile wise, but I get the error when I try to place the login control onto a view using the toolbox

    Cheers

    Paul

  • brian.noyes

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by brian.noyes on Aug 15, 2012 15:38

    Sorry, goes beyond the scope of the article, so seeking help for that here is not the right place. Shoot me an email and I may be able to point you in the right direction.

  • AndrewStephens

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by AndrewStephens on Nov 23, 2012 11:05

    I'm often put off by stuff that comes out of the MS Patterns & Practices team, mainly due to lack of good documentation and examples. Your article has certainly demystified Prism navigation, thanks. Just a couple of questions though:-

    If you were to use a ContentControl to host the customer edit views, I guess you'll only ever see one view at a time, so what happens to the others? Do they just sit around out of sight until the app is closed? Is there a way to dispose of a view or request it to be GC'd when that view is navigated away from?

    Each time you navigate to a customer edit view it creates a new tab in the tab control (assuming the ID is different each time). Have you written code to do this, or does it happen "automagically" because Prism knows what to do with a tab control? If so, are there any other WPF controls that Prism navigation handles in a similar, special way? I've read somewhere that you can use Prism navigation with (say) a listbox - so would each view appear as an item in the list?

  • brian.noyes

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by brian.noyes on Nov 23, 2012 16:18

    Hi Andrew,

    Great questions. I do find your comment about documentation and samples strange though - those are the two things that I typically cite as one of the strengths of p&p guidance. Go find me other open source projects out there that have as thorough of documentation as a whole book + online supplements as part of their documentation: http://compositewpf.codeplex.com/releases/view/55580. It comes with two full blown app samples (the Stock Trader RI and the MVVM RI) and close to a dozen QuickStarts for separate features of Prism. That seems like pretty darn good docs and samples to me.

    In answer to the question on ContentControl and TabControl, there is a shared answer here - Prism has what are called RegionAdapters - the thing that bridges between the specific container control that is tagged as a region and the IRegion API itself (Add, Activate, Remove, etc). The RegionAdapter will maintain its own list of views that have been added to it, and will do the right thing with the container's API to show those views. So for a ContentControl, it allows you to add multiple views, will Activate the first one that you add, and you can Activate other ones to achieve navigation within that ContentControl. Behind the scenes, the ContentControlRegionAdapter has logic that says "Activate to me means set the Content property of the ContentControl to the Activated view". The TabControl has logic that says "each Add means put that view in a tab, and Activate means set that as the SelectedItem". In addition, in the Silverlight case, the TabControlRegionAdapter also has to do some additional gymnastics to get the DataTemplate to marry up the view because implicit data templates don't automatically flow down into the ContentControl that is inside a TabItem in a TabControl.

    Unfortunately Prism does not do any IDisposable handling of the views or their ViewModels. So you do have to actively manage calling IDisposable at the right time outside the Prism code. That was something the team felt could not be easily generalized in the Prism code since an IDisposable object is not supposed to be used after disposal, we didn't think the framework had enough information to know when the right point was to kill something, it just makes it so you can get it hosted in a container or remove it without being coupled to that container. You could potentially write a custom region adapter (derived from one of the built in ones) that handled that if you wanted to encapsulate a predictable pattern for disposal.

    Prism has built in RegionAdapeters for ContentControl, ItemsControl, and Selector. So anything derived from those (i.e. ListBox) have a good chance of working as a region. But it all depends on how they go about rendering their contents. A DataGrid for example is not a general purpose container for child items even though it is a Selector. Likewise some of the third party component vendors have controls like Docking containers that may be an ItemsControl, but may not work out of the box with the ItemsControl adapter we have in there. 

    Hope that helps

    Brian

  • ethan

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by ethan on Dec 04, 2012 20:15

    I have a sort of "project" setup in my application where users can store their work (work being items in an "Order" for example). Only one project is active at a time, and there is a master-detail setup for the items in an order. For the case of adding items to an order, I would like for the master area to be a prism region (ItemsControl) allowing me to easily navigate/populate as items are selected/added. For speed's sake, I would like to keep multiple instances of the master-detail view in the main region (instead of creating/removing constantly), only activating the one corresponding to the open project. Would my the ItemsControl master region be violating the unique region name then? Maybe more simply worded, can there be multiple regions that technically have the same name but only one is ever in an active region?

    I realize this is similar to algodfried's question, but your statement "two instances of the same parent view that contains a region alive at the same time" gave me hope if by "alive" you mean active.

    Thanks again for this great article series!

  • ethan

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by ethan on Dec 04, 2012 21:29

    Realized it would be simple to mock that up and give it a try, sure enough it fails. I'm going to look into the scoped Regions, but I am seeing a lot of complexity as you mentioned. I suppose it might even be worth it to not worry with keeping the not-open projects as inactive views in the region. I had been experiencing delay when navigating to the master-detail, but that was before I did a lot of refactoring to use the patterns established with Prism.

  • BennyPedersen

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by BennyPedersen on Feb 10, 2013 14:36

    Navigation does not update screen. Do I need to hook up some PropertyChangedEvent?

    I have a Silverlight application on the way. I'm trying to set up the navigation as in this article and apparently everything is working. From a menu I switch the content on the maincontent. When I debug, I can see, that all navigation to and from are executed and I get a navigationResult = true. In the RegionManager, I can see, that all the needed views are loaded for that region, but in the end, nothing changes on the screen. Initially the views load and are shown in the MainContent, when I press the menu buttons, but as soon as they are loaded, the actual MainContent are not updated if I call an existing view. The views are set to be CreationPolicy.Shared.

  • BennyPedersen

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by BennyPedersen on Feb 10, 2013 14:50

    Navigation does not update screen. Do I need to hook up some PropertyChangedEvent?

    I have a Silverlight application on the way. I'm trying to set up the navigation as in this article and apparently everything is working. From a menu I switch the content on the maincontent. When I debug, I can see, that all navigation to and from are executed and I get a navigationResult = true. In the RegionManager, I can see, that all the needed views are loaded for that region, but in the end, nothing changes on the screen. Initially the views load and are shown in the MainContent, when I press the menu buttons, but as soon as they are loaded, the actual MainContent are not updated if I call an existing view. The views are set to be CreationPolicy.Shared.

  • brian.noyes

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by brian.noyes on Feb 10, 2013 17:48

    Hi Benny,

    How are you hooking up your views and view models? Statically in the XAML? Are you using DataTemplates?

    I assume you are using RegionManager.RequestNavigate to do the navigation - have you confirmed that you get a success callback? Its an async method. Are you passing a view instance to navigate to or a view model that gets hooked up dynamically with a data template?

    Its hard to help out with this kind of thing just through comments.

  • BennyPedersen

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by BennyPedersen on Feb 11, 2013 11:53

    Hi Brian

    I do use static loading of the view model in XAML. What I try to do is to switch the view in the MainContent area, by pushing buttons in a menu. I have followed your example in this article for setting up the views and do something like this:

    Button 1 click;

    RegionManager.RequestNavigate("MainContent", "PublicHomeView", PostNavigationCallback);

     

    Button 2 click:

    RegionManager.RequestNavigate("MainContent", "DemoCompanyView", PostNavigationCallback);

     

    In the PostNavigationCallback, I get navigationResult.Result true.

    When I start up the program and I press the first button, the MainContent shows the correct view. When I press the second button it also shows the expected view, but when both views are present in the RegionManager and I press the buttons, nothing happens, eventhouh it still gives navitationResult.Result true.

    I actually think, that the RegionManager is doing its job, but the MainContent region somehow needs to be notified, that the content has been changed or something like that?

    Is there a way to see, which view are the active in RegionManager?

     

    navigationResult.Result

  • myomintin

    Re: Working with Prism 4 Part 4: Region Navigation


    posted by myomintin on Sep 23, 2013 09:07
    silverlightshow.net should support download resume capability for downloadable file.

Add Comment

Login to comment:
  *      *       

From this series