Navigating Views using a M-V-VM

161 views
Skip to first unread message

Corrado Cavalli

unread,
Nov 4, 2008, 5:14:32 PM11/4/08
to wpf-di...@googlegroups.com

Hi folks,

I’ve read tons of docs about M-V-VM and now I have (I hope) quite clear scenario about how to use it, but I frankly haven’t seen any sample of how to navigate between various windows of a WPF application that uses MVVM pattern in a way that it is obviously extensible/unit testable.

Do you have any sample, idea, links etc on this?

 

Thanks

Corrado

 

 

Josh Smith

unread,
Nov 4, 2008, 6:14:21 PM11/4/08
to wpf-di...@googlegroups.com
When you say 'navigate' what do you mean? Wizard-style nav? Opening a new window? Navigation to a new page? All of the above?

Hi folks,

Thanks

Corrado


[The entire original message is not included]

Bill Kempf

unread,
Nov 4, 2008, 6:49:45 PM11/4/08
to wpf-di...@googlegroups.com
My goal is all of the above.  Haven't gotten the right formula just yet.
--
Quidquid latine dictum sit, altum sonatur.
- Whatever is said in Latin sounds profound.

War is peace. Freedom is slavery.  Bugs are features.

Karl Shifflett

unread,
Nov 4, 2008, 7:02:27 PM11/4/08
to wpf-di...@googlegroups.com

I’ll be posting a Code Project article soon with this built-it.

 

Karl

Corrado Cavalli

unread,
Nov 5, 2008, 12:21:32 AM11/5/08
to wpf-di...@googlegroups.com
Ideally all of above (Navigation in Silverlight might be another
interesting thread, suggestion welcome!) but for the moment opening a new
window might be enough...

Thanks
Corrado

-----Original Message-----
From: wpf-di...@googlegroups.com [mailto:wpf-di...@googlegroups.com]

Paul Stovell

unread,
Nov 5, 2008, 1:33:03 AM11/5/08
to wpf-di...@googlegroups.com
Hi Corrado,

So the way I see it there's effectively two navigation models we're talking about - launching Windows, or some kind of page-based navigation like WPF's Navigation system. There are also two approaches to MVVM (Presentation Model) - one where the View drives UI things, and the PM/VM is just a container for some business logic; or one where you really want your PM/VM to drive all navigation too.

With a view-first approach (which is perfectly valid, and my favourite) navigation is easy - window.Show(), NavigationService.navigate(page2), etc. Using the WPF navigation system there are some good samples in the SDK for navigation topologies. 
  • You can think about page-based navigation as essentially a view-driven linked list, where each view knows about the next. If you're following view-first MVVM/presentation model this works well. It does push a little knowledge into the view about going to the next page though.
  • Another approach is to use a navigation coordinator. In this sense, the navigation coordinator is given some information ("the user selected account A") and decides which page comes next ("if blah return new Page2") but allows the view to perform the actual navigation (for PageFunctions, this is required). This allows the view to say "Go to the next page", without knowing what that next page is.
Now, if you want navigation to be managed by the VM/PM, you could create an interface and adapter for INavigationService and interfaces for each page/window (IPage2, ICustomerDetailsIWindow etc.) and resolve the services from your IOC container.

You could then create an interface that wraps all display strategies: IViewService

class ViewService : IViewService
{
    void ShowView(IView originalView, IView newVIew)
    {
         if (newView is Page && originalView is Page)
         {
             ((Page)originalView).NavigationService.Navigate(newView);
         }
         else if (newView is Page)
         {
             // Launch a new navigation window, or maybe add a Frame to a Region via a Prism RegionManager
             new WizardWindow(newView).Show();
         }
         else if (newView is Window)
         {
             ((Window)newView).ShowDialog(originalView);
         }
         else if (newView is Control)
         {
              regionManager.Regions["Content"].Add(newView).Activate(newView);
         }
    }
}

Of course as a good developer, you'd wrap those "ifs" into a Strategy pattern and resolve those from a container too.

void ShowView(IView originalView, IView newView)
{
      var strategies = ServiceLocator.Current.ResolveAll<IViewDisplayStrategy>();
      strategies.Where(s => s.CanShow(originalView, newView)).First().Display(originalView, newView);
      // TODO: handle the case where there isn't a strategy
}

You'd have to come up with an API that allows for modal/non-modal, or returning for page functions (your interface for every page could just define a Return event, so that is easy), as I'm sure everyone has different needs.

If your VM/PM is driving WPF navigation, and you really want PageFunctions (which may complicate things) here's how you could do it:

interface INavigableView<INextPage> : IView {
    void Navigate(INextPage nextView);
}

class CustomerListModel/Presenter
{
void GoToNextPage()   // in your ViewModel/PresenterModel
{
    var next = navigationController.Next<ICustomerDetailsPage>(this.SelectedCustomer);   // Give it the info it needs to make a decision
    ((INavigablePage<ICustomerDetailsPage>)this.View).Navigate(next);
}
}

// Assume CustomerList navigates to CustomerDetails
class CustomerListPage : INavigableView<ICustomerDetailsPage>
{
     public void Navigate(ICustomerDetailsPage next)
     {
          next.Return += ....    // This must always be done in the view - it sucks
          NavgiationService.Navigate(next);
     }
}


Needless to say, I think allowing the View to control navigation is a much simpler and easier to follow approach, but the above is one way you could manage it. You would also want to think about back/forward navigation.

Hope that gives you some ideas.

Paul
--
Paul Stovell
http://www.paulstovell.net

Josh Smith

unread,
Nov 5, 2008, 7:58:16 AM11/5/08
to wpf-di...@googlegroups.com
Awesome input, Paul!

Laurent Bugnion [MVP]

unread,
Nov 5, 2008, 8:22:41 AM11/5/08
to wpf-di...@googlegroups.com
Being a very pragmatic developer, I also prefer to have the View drive
the navigation, and use the VM to save the navigation state (last
visited page, history (if needed)) so that the user can retrieve those
things the next time he starts the application.

Cheers,
Laurent

Josh Smith wrote:
> Awesome input, Paul!
>
> On Wed, Nov 5, 2008 at 1:33 AM, Paul Stovell <sto...@gmail.com
> <mailto:sto...@gmail.com>> wrote:
>
> Hi Corrado,
>
> So the way I see it there's effectively two navigation models
> we're talking about - launching Windows, or some kind of
> page-based navigation like WPF's Navigation system. There are also
> two approaches to MVVM (Presentation Model) - one where the View
> drives UI things, and the PM/VM is just a container for some
> business logic; or one where you really want your PM/VM to drive
> all navigation too.
>
> With a view-first approach (which is perfectly valid, and my
> favourite) navigation is easy - window.Show(),
> NavigationService.navigate(page2), etc. Using the WPF navigation
> system there are some good samples in the SDK for navigation
> topologies.
>

> * You can think about page-based navigation as essentially a


> view-driven linked list, where each view knows about the
> next. If you're following view-first MVVM/presentation model
> this works well. It does push a little knowledge into the
> view about going to the next page though.

> * Another approach is to use a navigation coordinator. In this

--
Laurent Bugnion [Microsoft MVP, MCP]
Software engineering, Blog: http://www.galasoft.ch
PhotoAlbum: http://www.galasoft.ch/pictures
Support children in Calcutta: http://www.calcutta-espoir.ch


Corrado Cavalli

unread,
Nov 5, 2008, 9:18:07 AM11/5/08
to wpf-di...@googlegroups.com
Laurent,
Do you have any sample or link to share?

Corrado

-----Original Message-----
From: wpf-di...@googlegroups.com [mailto:wpf-di...@googlegroups.com]
On Behalf Of Laurent Bugnion [MVP]
Sent: mercoledì 5 novembre 2008 14:23
To: wpf-di...@googlegroups.com
Subject: [WPF Disciples] Re: Navigating Views using a M-V-VM

Laurent Bugnion [MVP]

unread,
Nov 5, 2008, 9:39:17 AM11/5/08
to wpf-di...@googlegroups.com
Hey Corrado,

Sorry, I don't. The code where we used this approach is not public. If I
have time I will try to create a sample.

Cheers,
Laurent

Dr. WPF

unread,
Nov 5, 2008, 1:04:27 PM11/5/08
to wpf-di...@googlegroups.com

I have also favored the view-driven navigation in the past.  However, over the last couple of years, more and more clients are asking for the ability to have both a windows client and web view of their application.  As such, I've been putting more of the driving logic in the viewmodel and making the view more of a state representation.

Having the viewmodel drive navigation definitely adds complexity.  For example, consider a password dialog which consists of a field for domain, username, and password.  When the logon command in the viewmodel executes, it may fail for any number of reasons.  Suppose the user forgot to specify the domain.  For the best user experience, after the validation failure you will want to focus whatever control is used to specify the domain.  Now you have mixed metaphors.  Typically, the notion of focus is purely a view thing, but now, only the viewmodel knows where focus *should* be.  Unfortunately, the viewmodel has no idea what controls actually exist in the view, nor should it.  This is just one example of the type of issues you must conquer in a viewmodel-driven navigation approach.

(Incidently, I solve the above problem by setting an IDataErrorInfo error against the viewmodel field that should have focus and passing a keyword (like "setfocus") as the error.  Then my view can handle and clear the resulting error without knowing or caring from where it derived.  The bubbled error event can be used to know which control should be focused.  Someday I'll have bandwidth to properly blog this approach. :))

My goal (except where poo interferes) is to always create a platform-agnostic viewmodel that will work equally well for both WPF and Silverlight views.  My viewmodel knows nothing about the presentation technology and my view knows very little about the inner workings of the viewmodel (although it clearly knows all about the public interface of the viewmodel because that is what it presents).

Dr. WPF - Online Office at http://www.drwpf.com/blog/


Josh Smith

unread,
Nov 5, 2008, 1:50:00 PM11/5/08
to wpf-di...@googlegroups.com
Mixing input focus with ViewModels is always an interesting problem.  One thing I've considered, though not yet tried out, is to have an attached behavior that listens for an event on the VM object, perhaps called RequestFocus, and gives each VM property a unique ID (such as the property name... :)  When the VM wants a certain logical field to be given focus, it could raise the RequestFocus event, passing in the property's ID in the event arg.  The attached behavior would then set focus to its target element when RequestFocus is raised and e.PropertyID equals the ID assigned to the attached property set on the element.

Josh

Corrado Cavalli

unread,
Nov 5, 2008, 2:51:36 PM11/5/08
to wpf-di...@googlegroups.com

Josh,

Your idea sounds cool!

I think that in general, while there’s a lot of material about MV-VM but there’s quite nothing about how to implement it in real world app (focus handing, navigating application windows, error handling, intercommunication between open windows etc…).

There are a lot of small day to day issues like: Let’s say a command should result in a messagebox displayed and, depending on user response different code must be run, how do you handle this scenario?

I personally use this path: Command cause raising of an event from ViewModel, this is subscribed by View code-behind where Messagebox.Show resides and depending on user choice I invoke method A or B  of the viewmodel, this pattern allow me to unit test the viewmodel.

 

Corrado

 

From: wpf-di...@googlegroups.com [mailto:wpf-di...@googlegroups.com] On Behalf Of Josh Smith
Sent: mercoledì 5 novembre 2008 19:50
To: wpf-di...@googlegroups.com
Subject: [WPF Disciples] Re: Navigating Views using a M-V-VM

 

Mixing input focus with ViewModels is always an interesting problem.  One thing I've considered, though not yet tried out, is to have an attached behavior that listens for an event on the VM object, perhaps called RequestFocus, and gives each VM property a unique ID (such as the property name... :)  When the VM wants a certain logical field to be given focus, it could raise the RequestFocus event, passing in the property's ID in the event arg.  The attached behavior would then set focus to its target element when RequestFocus is raised and e.PropertyID equals the ID assigned to the attached property set on the element.

Josh

Reply all
Reply to author
Forward
0 new messages