When navigation operations take place, you need to know what's happening so you can respond accordingly. The Frame control raises events that you can handle in the MainPage
class (the class that hosts the Frame control), while within a view you can choose to either handle the events on the
NavigationService
object or simply override the navigation methods on the view itself (which are inherited from the Page
class).
The Frame control provides the following events that enable you to respond to navigation operations and their current statuses:
Navigating
Navigated
NavigationStopped
NavigationFailed
FragmentNavigation
The Navigating
event is raised before a navigation operation actually takes place, while the
Navigated
event is raised after the operation is complete. If you want to stop the navigation operation from actually taking place, you can set the value of e.Cancel
to true
in the Navigating
event handler.
The NavigationStopped
event is raised when the StopLoading
method on the Frame control or the NavigationService
object is called. The NavigationFailed
event is raised if the application navigated to an invalid deep link—that is, one that couldn't be mapped to a view by the URI mapper—or the user manually entered an invalid deep link as part of the URI in the browser's address bar.
The FragmentNavigation
event is raised instead of the Navigating
/Navigated
events in a couple of different scenarios. If you start a navigation operation for the view that is currently active in the Frame and you are passing in the same parameters that were passed to the view previously, the
FragmentNavigation
event is raised. The view is not reloaded. An example of this is clicking the Home button to navigate to the Home
view while you are already there. This event might be useful when you need to know that a navigation operation has taken place but the view was not reloaded. This event would also be raised if you were to start a navigation operation and have appended a fragment to the end of the URI to navigate to. For example, you might try this navigation operation:
ContentFrame.Navigate(new Uri("ProductDetails/879#StockLevels", UriKind.Relative));
Note the #
used to indicate the start of the fragment. This syntax might be initially confusing, as the start of the deep link in the resulting URI, which points to the view, is indicated by the same symbol (#
). However, you will find that the resulting URI is as follows:
ProductDetails/879$StockLevels
As you can see, the #
is converted to a $
, which now indicates the start of the fragment. The purpose of having a fragment in a URI will depend on your needs, but you can easily access its value via the e.Fragment
property, which is passed in as a parameter to the FragmentNavigation
event handler.
A scenario where you might want to hook into the navigation events on the Frame control might be when you have a toolbar on the Frame host page that needs to know when the active view has been changed in the Frame so that it can highlight the appropriate toolbar button. You can implement this requirement by handling the Navigated
event on the Frame control. You can actually find this exact scenario already implemented for you in the default Silverlight Navigation Application project template. The MainPage
class handles the Navigated
event and changes the styles on the buttons according to whether its corresponding view is currently open. Note also that it handles the NavigationFailed
event and displays an error message window if that event is raised.
There are two methods of responding to a navigation operation within a view. The first is to add an event handler to an event on the NavigationService
object (obtained by the NavigationService
property on the view), like so:
NavigationService.Navigating += NavigationService_Navigating;
The same events that were available on the Frame control are available on the NavigationService
object.
Note You cannot add event handlers for the NavigationService
's events in the view's constructor, as the NavigationService
object will be null at that point and will result in a NullReferenceException
being thrown. You should add any event handlers in the view's Loaded
event handler instead.
Alternatively, you can override any of the following virtual methods in the view's class, inherited from the Page
class, that you want to respond to:
OnNavigatedTo
OnNavigatingFrom
OnNavigatedFrom
OnFragmentNavigation
Note that there are no overridable methods corresponding to the NavigatingTo
, NavigationStopped
, or NavigationFailed
events on the NavigationService
object, but there are two new “events” that we can handle: OnNavigatingFrom
and OnNavigatedFrom
. One use for overriding the OnNavigatingFrom
method is to check whether the current data form is dirty (that is, has unsaved changes) and ask the user whether the changes should be saved before moving away from the view. The navigation operation can be cancelled from within this method by setting the value of e.Cancel
to true
.
Note The NavigatedTo
event is raised before the Loaded
event on the view.