I read that a few people were having a problem with this so I wanted to post a (somewhat) elegant solution I came up with while trying to deal with this. The problem is when you create templated pages in Silverlight and the ContentControls do not have the parent Frame's NavigationService (it's always null when you try and use it). There are similar scenarios where a NavigationService is present in intellisence but is always null. To enable site-wide Navigation:
Create a new UserControl
(I called mine 'NavFrame') that has a Navigation Frame in it (I called mine 'RootFrame').
Inside this Frame you can set whatever content you like.
Set this UserControl as your RootVisual
in App.xaml.cs (i.e. this.RootVisual = new NavFrame();
).
To use the NavigationService in any of your pages you can type something like:
((NavFrame)App.Current.RootVisual).RootFrame.NavigationService
.Navigate(new Uri("Your Uri", UriKind.RelativeOrAbsolute));
You can create an Action and drag it on top of the control you want to make navigation happen, just like this one:
public class NavigateAction : TriggerAction<DependencyObject>
{
public Uri Uri
{
get;
set;
}
protected override void Invoke(object parameter)
{
var frame = FindContainingFrame(AssociatedObject);
if(frame == null)
throw new InvalidOperationException("Could not find the containing Frame in the visual tree.");
frame.Navigate(Uri);
}
protected static Frame FindContainingFrame(DependencyObject associatedObject)
{
var current = associatedObject;
while(!(current is Frame))
{
current = VisualTreeHelper.GetParent(current);
if(current == null)
return null;
}
return (Frame)current;
}
}
Now you just have to drag it and wire it to your target page. BTW this is true for SL4, never tried it on SL3. and the URI does work in the form: "/SilverlightApplication1;component/Page1.xaml" or with UriMapping on the Frame.
((Frame)(Application.Current.RootVisual as MainPage).FindName("ContentFrame"))
.Navigate(new Uri("Page Name", UriKind.Relative));