Basically, no, not that's built-in. Complex parameters like IRepository instances are, unfortunately, beyond the ability of the navigation facilities in Silverlight; I usually use some form of IoC container to handle those. Simpler POCO parameters are easily serialized to a string, but that still requires magic strings and manual query-string parsing.
You can, however, easily build something typesafe yourself. For example, here's my approach.
For parameter data, I have a class that I call 'Extras', which wraps a Dictionary<string, object>
with methods like GetBool(string)
, GetInt32(string)
, etc., and has a static factory method CreateFromUri(Uri)
; this is good enough for my purposes.
I use this in conjunction with type-safe navigation. I really like the MVVM pattern, and each of my pages has a ViewModel encapsulating nearly all logic. The one-to-one relationship of page to ViewModel makes the latter an ideal navigation key. That, combined with attributes and reflection, gives us a simple solution:
public class NavigationTargetAttribute : Attribute
{
private readonly Type target;
public ViewModelBase Target
{
get { return target; }
}
public NavigationTargetAttribute(Type target)
{
this.target = target;
}
}
Put one of these on each of your pages, with the proper ViewModel type.
[NavigationTarget(typeof(LoginViewModel))]
public class LoginPage : PhoneApplicationPage
{ ... }
Then, in a singleton NavigationManager-esque class, you can do:
GetType().Assembly
.GetTypes()
.Select(t => new { Type = t, Attr = t.GetCustomAttributes(false).FirstOrDefault(attr => attr is NavigationTargetAttribute) })
.Where(t => t.Attr != null);
And just like that, you have a collection of every navigable type in your app. From there, it's not much more work to put them in a dictionary, for example. If you follow a convention for where you put your pages, you can (for example) translate between type and Uri quite easily... for example, new Uri("/Pages/" + myPageType.Name + ".xaml", UriKind.Relative)
. It's not much more to add support for query parameters. Finally, you'll end up with a method, like so:
public void Navigate(Type target, Extras extras)
{
Type pageType;
if (navigationTargets.TryGetValue(target, out pageType))
{
var uri = CreateUri(pageType, extras);
navigationService.NavigateTo(uri);
}
// error handling here
}
Finally, in the page's OnNavigatedTo
method, I do something like:
var extras = Extras.CreateFromUri(e.Uri);
((ViewModelBase) DataContext).OnNavigatedTo(extras);
This, finally, gives a semblance of strongly-typed navigation. This is a bare-bones approach; off the top of my head, this could be improved by adding required parameters in the navigation attribute and validating them at navigation-time. It also doesn't support more complex types of navigation, where the value of nav arguments would determine the ultimate destination. Nevertheless, this suits my 90% use case - maybe it will work for you, too.
There are definitely some details omitted here, like how exactly to get an instance of NavigationService
- I can work up a more complete sample later tonight, but this should be enough to get started.